读书人

Java多线程编程#线程等候机制

发布时间: 2013-02-24 17:58:56 作者: rapoo

Java多线程编程#线程等待机制
1、最佳的模型是:生产者-消费者

package com.boonya.multithread.explain;/** ==============================================   * 文件:ProducerAndConsumer.java   * 描述:生产者--消费者  [生产者生产了之后消费者才能消费] * 注:引入了等待通知(wait/notify)机制如下:   1、在生产者没有生产之前,通知消费者等待;在生产者生产之后,马上通知消费者消费。   2、在消费者消费了之后,通知生产者已经消费完,需要生产。  * ============================================ */  public class ProducerAndConsumer { public static void main(String argv[]){     ShareData    s = new ShareData();     new Consumer(s).start();     new Producer(s).start();    }   }class ShareData{        private char c;    // 通知变量    private boolean writeable = true;      // -------------------------------------     // 需要注意的是:在调用wait()方法时,需要把它放到一个同步段里,否则将会出现    // "java.lang.IllegalMonitorStateException: current thread not owner"的异常。    // -------------------------------------    public synchronized void setShareChar(char c){    if (!writeable){      try{       // 未消费等待       wait();      }catch(InterruptedException e){}   }            this.c = c;       // 标记已经生产       writeable = false;       // 通知消费者已经生产,可以消费       notify();    }        public synchronized char getShareChar(){    if (writeable){      try{       // 未生产等待       wait();      }catch(InterruptedException e){}      }        // 标记已经消费        writeable = true;        // 通知需要生产        notify();        return this.c;      }   }      // 生产者线程   class Producer extends Thread{       private ShareData s;        Producer(ShareData s){     this.s = s;    }        public void run(){    for (char ch = 'A'; ch <= 'Z'; ch++){      try{          Thread.sleep((int)Math.random() * 400);      }catch(InterruptedException e){}            // 生产      s.setShareChar(ch);      System.out.println(ch + " producer by producer.");     }    }   }      // 消费者线程   class Consumer extends Thread{       private ShareData s;        Consumer(ShareData s){     this.s = s;    }        public void run(){     char ch;          do{     try{       Thread.sleep((int)Math.random() * 400);   }catch(InterruptedException e){}      // 消费      ch = s.getShareChar();      System.out.println(ch + " consumer by consumer.");     }while(ch != 'Z');    }   }   


2、等待程序结束
package com.boonya.multithread.explain;/**===================================  * 文件:LetOneThreadSleepAfterAnotherReady.java  * 描述:等待一个线程的结束的两种方法  * ====================================  */  public class LetOneThreadSleepAfterAnotherReady { class  MyTaskThread extends Thread{public MyTaskThread(){}@Overridepublic void run() { for (int count = 1,row = 1; row < 20; row++,count++)        {           for (int i = 0; i < count; i++)           {              System.out.print('*');           }           System.out.println();        }   } }  // 第一种方法:不断查询第一个线程是否已经终止,如果没有,则让主线程睡眠一直到它终止为止    // 即:while/isAlive/sleep  public void Method1(){   MyTaskThread th1 = new MyTaskThread();   MyTaskThread th2 = new MyTaskThread();       // 执行第一个线程       th1.start();       // 不断查询第一个线程的状态       while(th1.isAlive()){         try{            Thread.sleep(100);         }catch(InterruptedException e){         }       }       //第一个线程终止,运行第二个线程       th2.start();     }          // 第二种方法:join()     public void Method2(){     MyTaskThread th1 = new MyTaskThread();     MyTaskThread th2 = new MyTaskThread();     // 执行第一个线程       th1.start();       try{         th1.join();       }catch(InterruptedException e){       }       // 执行第二个线程       th2.start();   }   public static void main(String[] args) { LetOneThreadSleepAfterAnotherReady mythread=new LetOneThreadSleepAfterAnotherReady();// mythread.Method1(); mythread.Method2();}}
1 楼 zjuttsw 昨天 提一点意见:
Object的wait方法(包括它的重载方法),应该始终包含在循环中。否则会造成数据不一致现象。原因是当线程调用wait方法时进入等待队列,当被其它线程唤醒时(notify or notifyAll),它会执行wait语句后面的指令。而不会再判断条件是否满足。
因此应该这样写:
public synchronized void setShareChar(char c){
while (!writeable){ /* 把 if 改成 while */
try{
// 未消费等待
wait();
}catch(InterruptedException e){}
}
同理getShareChar方法也应该把if改成while。 2 楼 zjuttsw 昨天 zjuttsw 写道提一点意见:
Object的wait方法(包括它的重载方法),应该始终包含在循环中。否则会造成数据不一致现象。原因是当线程调用wait方法时进入等待队列,当被其它线程唤醒时(notify or notifyAll),它会执行wait语句后面的指令。而不会再判断条件是否满足。
因此应该这样写:
public synchronized void setShareChar(char c){
while (!writeable){ /* 把 if 改成 while */
try{
// 未消费等待
wait();
}catch(InterruptedException e){}
}
同理getShareChar方法也应该把if改成while。
同时因为wait和notify的使用比较困难,容易出错。因此在JDK 1.5版本以后,不建议再使用notify和wait方法。一个更好的方法是使用Java大师(Doug Lea)编写的java.util.concurrent并行包里的API来实现。 3 楼 boonya 21 小时前 zjuttsw 写道zjuttsw 写道提一点意见:
Object的wait方法(包括它的重载方法),应该始终包含在循环中。否则会造成数据不一致现象。原因是当线程调用wait方法时进入等待队列,当被其它线程唤醒时(notify or notifyAll),它会执行wait语句后面的指令。而不会再判断条件是否满足。
因此应该这样写:
public synchronized void setShareChar(char c){
while (!writeable){ /* 把 if 改成 while */
try{
// 未消费等待
wait();
}catch(InterruptedException e){}
}
同理getShareChar方法也应该把if改成while。
同时因为wait和notify的使用比较困难,容易出错。因此在JDK 1.5版本以后,不建议再使用notify和wait方法。一个更好的方法是使用Java大师(Doug Lea)编写的java.util.concurrent并行包里的API来实现。

谢谢指点!

读书人网 >编程

热点推荐