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(){}
@Override
public 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();
}
}
分享到:
2013-02-16 15:37
浏览 861
评论
3 楼
boonya
2013-02-18
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来实现。
谢谢指点!
2 楼
zjuttsw
2013-02-17
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来实现。
1 楼
zjuttsw
2013-02-17
提一点意见:
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。