【线程同步】java实现生产者消费者问题与线程中的wait与notify总结

JAVA解决线程模型有三种方式,只讲一种,主要讲使用生产和消费的方式和线程同步。

(更多参见:java实现生产者消费者问题 - rhino - 博客园
http://www.cnblogs.com/happyPawpaw/archive/2013/01/18/2865957.html)

  1、wait()和notify()

引言

  生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况:

生产者消费者图

  存储空间已满,而生产者占用着它,消费者等着生产者让出空间从而去除产品,生产者等着消费者消费产品,从而向空间中添加产品。互相等待,从而发生死锁。

import java.util.LinkedList;

public class ProducerConsumer {
	private LinkedList<Object> storeHouse = new LinkedList<Object>();
	private int MAX = 10;

	public ProducerConsumer() {
	}

	public void start() {
		new Producer().start();
		new Comsumer().start();
	}

	class Producer extends Thread {
		public void run() {
			while (true) {
				synchronized (storeHouse) {
					try {
						while (storeHouse.size() == MAX) {
							System.out
									.println("storeHouse is full , please wait");
							storeHouse.wait();
						}
						Object newOb = new Object();
						if (storeHouse.add(newOb)) {
							System.out
									.println("Producer put a Object to storeHouse");
							Thread.sleep((long) (Math.random() * 3000));
							storeHouse.notify();
						}
					} catch (InterruptedException ie) {
						System.out.println("producer is interrupted!");
					}

				}
			}
		}
	}

	class Comsumer extends Thread {
		public void run() {
			while (true) {
				synchronized (storeHouse) {
					try {
						while (storeHouse.size() == 0) {
							System.out
									.println("storeHouse is empty , please wait");
							storeHouse.wait();
						}
						storeHouse.removeLast();
						System.out
								.println("Comsumer get  a Object from storeHouse");
						Thread.sleep((long) (Math.random() * 3000));
						storeHouse.notify();
					} catch (InterruptedException ie) {
						System.out.println("Consumer is interrupted");
					}

				}
			}

		}
	}

	public static void main(String[] args) throws Exception {
		ProducerConsumer pc = new ProducerConsumer();
		pc.start();
	}
}

JAVA中的Wait() 和notify()方法在API中的解释:


void java. lang. Object.wait() throws InterruptedException

Causes current thread to wait until another thread invokes the java.lang.Object.notify() method or the java.lang.Object.notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).

The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:

     synchronized (obj) {
         while (<condition does not hold>)
             obj.wait();
         ... // Perform action appropriate to condition
     }
 
This method should only be called by a thread that is the owner of this object's monitor. See the notify method for a description of the ways in which a thread can become the owner of a monitor.
Throws:
IllegalMonitorStateException - if the current thread is not the owner of the object's monitor.
InterruptedException - if another thread interrupted the current thread before or while the current thread was waiting for a notification. The interrupted status of the current thread is cleared when this exception is thrown.
See Also:
java.lang.Object.notify()
java.lang.Object.notifyAll()
http://tool.oschina.net/uploads/apidocs/jdk-zh/java/lang/Object.html#wait()

wait

public final void wait()
                throws InterruptedException
在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。

当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。

对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用:

synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
     }
 
此方法只应由作为此对象监视器的所有者的线程来调用。有关线程能够成为监视器所有者的方法的描述,请参阅 notify 方法。

抛出:
IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。
InterruptedException - 如果在当前线程等待通知之前或者正在等待通知时,任何线程中断了当前线程。在抛出此异常时,当前线程的 中断状态 被清除。
另请参见:
notify(), notifyAll()

void java. lang. Object.notify()

Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of the wait methods.

The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.

This method should only be called by a thread that is the owner of this object's monitor. A thread becomes the owner of the object's monitor in one of three ways:

  • By executing a synchronized instance method of that object.
  • By executing the body of a synchronized statement that synchronizes on the object.
  • For objects of type Class, by executing a synchronized static method of that class.

Only one thread at a time can own an object's monitor.

Throws:
IllegalMonitorStateException - if the current thread is not the owner of this object's monitor.
See Also:
java.lang.Object.notifyAll()
java.lang.Object.wait()

notify

public final void notify()
唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。

直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。

此方法只应由作为此对象监视器的所有者的线程来调用。通过以下三种方法之一,线程可以成为此对象监视器的所有者:

  • 通过执行此对象的同步实例方法。
  • 通过执行在此对象上进行同步的 synchronized 语句的正文。
  • 对于 Class 类型的对象,可以通过执行该类的同步静态方法。

一次只能有一个线程拥有对象的监视器。

抛出:
IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。
另请参见:
notifyAll(), wait()

notifyAll

public final void notifyAll()
唤醒在此对象监视器上等待的所有线程。线程通过调用其中一个 wait 方法,在对象的监视器上等待。

直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。

此方法只应由作为此对象监视器的所有者的线程来调用。有关线程能够成为监视器所有者的方法的描述,请参阅 notify 方法。

抛出:
IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。
另请参见:
notify(), wait()


JAVA中的Wait() 和notify()方法使用时应注意些什么

 Wait()和notify():如果条件不满足,则等待。当条件满足时,等待该条件的线程将被唤醒。一般用在synchronized机制中例如:

            线程A

                

synchronized(obj) {
		   while(!condition) {

                          obj.wait();

                                     }

                            obj.doSomething();

                             }

当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait()。

                  在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:

                线程B.

                   

             synchronized(obj)
		   {condition = true;obj.notify();}

                  需要注意的概念是: ◆调用obj的wait(),
notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {……} 代码段内。
◆调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {……}
代码段内唤醒A. ◆当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
◆如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
◆obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
◆当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。


所以,这两个 方法,并不是在同一个线程里面使用的,也不是在同一个synchronized里面使用的,而是在一个里面使用wait, 另 一个使用notify,一个notify,多个wait,但是唤醒哪个,由系统决定。

使用synchronized里面的obj.wait/obj.notify,意思是调用当前线程的wait/notify方法。


更多参考:

java实现生产者消费者问题 - rhino - 博客园
http://www.cnblogs.com/happyPawpaw/archive/2013/01/18/2865957.html

在线文档-jdk-zh
http://tool.oschina.net/apidocs/apidoc?api=jdk-zh

JAVA中的Wait() 和notify()方法使用时应注意些什么?_百度知道
http://zhidao.baidu.com/link?url=uvUlSTTZ7Ab99LJn4UJx-2azjs64vmizkoAT77Kt7EKZBU0MWphL5xCu_SlaF3L__mqwialDuOPTDGgF_pcDvK


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不止鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值