1. 程式人生 > >wait、notify、notifyAll

wait、notify、notifyAll

標註的解釋

/**
     * 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 {@code wait} methods.
	 
	 喚醒在這個物件的鎖上等待的單個執行緒。如果有多個執行緒在這個物件上等待,
	 其中一個執行緒被選擇喚醒。選擇是任意的,並在執行的自由裁量權發生。執行緒通過呼叫 wait 方法在物件的鎖上等待。
     * <p>
     * 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.
     * <p>
		
	在當前執行緒放棄對該物件的鎖定之前,喚醒執行緒將無法繼續進行。
        喚醒執行緒將以通常的方式與任何可能在該物件上進行同步競爭的執行緒進行競爭;
        例如,喚醒執行緒在作為下一個執行緒來鎖定該物件時不享有特權或也沒有劣勢。

     * 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:
      
       此方法只能由 持有這個物件鎖的執行緒 才能呼叫。 執行緒成為物件鎖的所有者有以下3種方式:
          
          1、通過執行物件的 synchronized  例項方法
          2、通過執行物件 synchronized 程式碼塊的主體
	      3、通過執行類的靜態 synchronized 方法
	
     * <ul>
     * <li>By executing a synchronized instance method of that object.
     * <li>By executing the body of a {@code synchronized} statement
     *     that synchronizes on the object.
     * <li>For objects of type {@code Class,} by executing a
     *     synchronized static method of that class.
     * </ul>
     * <p>
     * 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        java.lang.Object#notifyAll()
     * @see        java.lang.Object#wait()
     */
    public final native void notify();

    /**
     * Wakes up all threads that are waiting on this object's monitor. A
     * thread waits on an object's monitor by calling one of the
     * {@code wait} methods.
	 
	   喚醒所有在 物件鎖上等待的 執行緒。  一個執行緒呼叫 物件的 wait 方法就變成等待 物件鎖狀態
     * <p>
     * The awakened threads will not be able to proceed until the current
     * thread relinquishes the lock on this object. The awakened threads
     * will compete in the usual manner with any other threads that might
     * be actively competing to synchronize on this object; for example,
     * the awakened threads enjoy no reliable privilege or disadvantage in
     * being the next thread to lock this object.
     * <p>
     * This method should only be called by a thread that is the owner
     * of this object's monitor. See the {@code 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 this object's monitor.
     * @see        java.lang.Object#notify()
     * @see        java.lang.Object#wait()
     */
    public final native void notifyAll();

    /**
     * Causes the current thread to wait until either another thread invokes the
     * {@link java.lang.Object#notify()} method or the
     * {@link java.lang.Object#notifyAll()} method for this object, or a
     * specified amount of time has elapsed.
	 
	   使當前執行緒等待,直到另一個執行緒 執行了物件的 notify()、notifyAll() 方法。 或者指定的時間量已經過去
     * <p>
     * The current thread must own this object's monitor.
	   當前執行緒必須擁有 該物件的鎖。
     * <p>
     * This method causes the current thread (call it <var>T</var>) to
     * place itself in the wait set for this object and then to relinquish
     * any and all synchronization claims on this object. Thread <var>T</var>
     * becomes disabled for thread scheduling purposes and lies dormant
     * until one of four things happens:
	 
	   此方法使當前執行緒將其自身放置在該物件的等待集中。並放棄物件的鎖。直到發生下面四個方法才重新競爭鎖:
	       
		    1、一些另外的執行緒呼叫 物件的notify方法
			2、一些另外的執行緒
			
     * <ul>
     * <li>Some other thread invokes the {@code notify} method for this
     * object and thread <var>T</var> happens to be arbitrarily chosen as
     * the thread to be awakened.
     * <li>Some other thread invokes the {@code notifyAll} method for this
     * object.
     * <li>Some other thread {@linkplain Thread#interrupt() interrupts}
     * thread <var>T</var>.
     * <li>The specified amount of real time has elapsed, more or less.  If
     * {@code timeout} is zero, however, then real time is not taken into
     * consideration and the thread simply waits until notified.
     * </ul>
     * The thread <var>T</var> is then removed from the wait set for this
     * object and re-enabled for thread scheduling. It then competes in the
     * usual manner with other threads for the right to synchronize on the
     * object; once it has gained control of the object, all its
     * synchronization claims on the object are restored to the status quo
     * ante - that is, to the situation as of the time that the {@code wait}
     * method was invoked. Thread <var>T</var> then returns from the
     * invocation of the {@code wait} method. Thus, on return from the
     * {@code wait} method, the synchronization state of the object and of
     * thread {@code T} is exactly as it was when the {@code wait} method
     * was invoked.
     * <p>
     * A thread can also wake up without being notified, interrupted, or
     * timing out, a so-called <i>spurious wakeup</i>.  While this will rarely
     * occur in practice, applications must guard against it by testing for
     * the condition that should have caused the thread to be awakened, and
     * continuing to wait if the condition is not satisfied.  In other words,
     * waits should always occur in loops, like this one:
     * <pre>
     *     synchronized (obj) {
     *         while (<condition does not hold>)
     *             obj.wait(timeout);
     *         ... // Perform action appropriate to condition
     *     }
     * </pre>
     * (For more information on this topic, see Section 3.2.3 in Doug Lea's
     * "Concurrent Programming in Java (Second Edition)" (Addison-Wesley,
     * 2000), or Item 50 in Joshua Bloch's "Effective Java Programming
     * Language Guide" (Addison-Wesley, 2001).
     *
     * <p>If the current thread is {@linkplain java.lang.Thread#interrupt()
     * interrupted} by any thread before or while it is waiting, then an
     * {@code InterruptedException} is thrown.  This exception is not
     * thrown until the lock status of this object has been restored as
     * described above.
     *
     * <p>
     * Note that the {@code wait} method, as it places the current thread
     * into the wait set for this object, unlocks only this object; any
     * other objects on which the current thread may be synchronized remain
     * locked while the thread waits.
     * <p>
     * This method should only be called by a thread that is the owner
     * of this object's monitor. See the {@code notify} method for a
     * description of the ways in which a thread can become the owner of
     * a monitor.
     *
     * @param      timeout   the maximum time to wait in milliseconds.
     * @throws  IllegalArgumentException      if the value of timeout is
     *               negative.
     * @throws  IllegalMonitorStateException  if the current thread is not
     *               the owner of the object's monitor.
     * @throws  InterruptedException if any thread interrupted the
     *             current thread before or while the current thread
     *             was waiting for a notification.  The <i>interrupted
     *             status</i> of the current thread is cleared when
     *             this exception is thrown.
     * @see        java.lang.Object#notify()
     * @see        java.lang.Object#notifyAll()
     */
    public final native void wait(long timeout) throws InterruptedException;


wait、notify例子

public class WaitNotifyDemo1 {
	
	private static DateFormat format = new SimpleDateFormat("HH:mm:ss");
	
	private static boolean flag = true;
	
	private static Object lock = new Object();
	
	public static void main(String[] args) {
		
		Thread wt = new Thread(new WaitThread(),"wt");
		Thread nt = new Thread(new NotifyThread(),"nt");
		wt.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		nt.start();
	}
	
	private static class WaitThread implements Runnable{

		@Override
		public void run() {
			
			synchronized (lock) {
				try {
					// 獲得 物件 鎖
					System.out.println(format.format(new Date())+"  "+Thread.currentThread().getName()+" is ruuning; flag = "+flag );
					
					//當前執行緒等待,  放棄 lock鎖。等待喚醒
					lock.wait();
					
					System.out.println(format.format(new Date())+"  "+Thread.currentThread().getName()+" continue ruuning; flag = "+flag );
				} catch (InterruptedException e) {
					
					e.printStackTrace();
				}
				
				flag = true;
				System.out.println(format.format(new Date())+"  "+Thread.currentThread().getName()+" prepare to give up lock; flag = "+flag );
			}
			
		}
		
	}
	
	
	
	private static class NotifyThread implements Runnable{

		@Override
		public void run() {
			synchronized (lock) {
				
				System.out.println(format.format(new Date())+"  "+Thread.currentThread().getName()+" is ruuning; flag = "+flag );
				flag = false;
				//喚醒處於等待狀態其他執行緒
				lock.notify();
				System.out.println(format.format(new Date())+"  "+Thread.currentThread().getName()+" prepare to give up lock; flag = "+flag );
			}
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(format.format(new Date())+"  "+Thread.currentThread().getName()+" have given up lock; flag = "+flag );
			
		}
		
	}

}


生產者和消費者

public class ProducerConsumerDemo {
	
	/**
	 * 倉庫最大量
	 */
	private static Integer MAX_SIZE = 100;
	/**
	 * 倉庫
	 */
	private static LinkedList list = new LinkedList();
	
	public static void main(String[] args) {
		
		//生產者生產
		Thread p1 = new Thread(new producer(20));
		Thread p2 = new Thread(new producer(20));
		Thread p3 = new Thread(new producer(20));
		Thread p4 = new Thread(new producer(20));
		Thread p5 = new Thread(new producer(20));
		Thread p6 = new Thread(new producer(100));
		
		
		//消費者消費
		Thread c1 = new Thread(new consumer(50));
		Thread c2 = new Thread(new consumer(30));
		Thread c3 = new Thread(new consumer(20));
		
		
		//執行
		c1.start();
		c2.start();
		c3.start();
		
		p1.start();
		p2.start();
		p3.start();
		p4.start();
		p5.start();
		//p6.start();
		
	}
	
	
	/**
	 * 生產者
	 * @author chenzhengwei
	 *
	 */
	private static class producer implements Runnable{
		
		/**
		 * 生產數量
		 */
		private Integer num;
		
		public producer(Integer num) {
			this.num = num;
		}

		@Override
		public void run() {
			
			synchronized (list) {
				
				/**
				 * 倉庫容量不足
				 */
				while(list.size()+num > MAX_SIZE) {
					System.out.println("[倉庫最大容量]:"+MAX_SIZE+"  [生產者要生產的數量]:"+num+"  [現有庫存數量]:"+list.size()+"  倉庫容量不足停止生產");
					
					try {
						list.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
				/**
				 * 生產者生產
				 */
				for(int i = 1; i <= num; i++) {
					list.add(new Object());
				}
				
				System.out.println("[倉庫最大容量]:"+MAX_SIZE+"  [生產者已生產數量]:"+num+"  [現有倉庫庫存量]:"+list.size()+"  生產成功");
				
				/**
				 * 倉庫還有庫存,剩餘庫存,通知消費者消費或其他生產者生產
				 */
				list.notifyAll();
			}
			
		}
		
		
	}
	
	
	/**
	 * 消費者
	 * @author chenzhengwei
	 *
	 */
	private static class consumer implements Runnable {
		
		/**
		 * 消費數量
		 */
		private Integer num;
		
		public consumer(Integer num) {
			this.num = num;
		}

		@Override
		public void run() {
			
			synchronized (list) {
				
				while(list.size() < num) {
                    System.out.println("[倉庫最大容量]:"+MAX_SIZE+"  [消費者要消費的數量]:"+num+"  [現有庫存數量]:"+list.size()+"  庫存數量不足無法消費");
					
					try {
						list.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
				}
				
				for(int i = 1; i <= num; i++) {
					list.remove();
				}
				
				System.out.println("[倉庫最大容量]:"+MAX_SIZE+"  [消費者已消費數量]:"+num+"  [現有倉庫庫存量]:"+list.size()+"  消費成功");
				
				/**
				 * 倉庫還有庫存,剩餘庫存,通知生產者生產或其他消費者消費
				 */
				list.notifyAll();				
			}
			
		}
		
		
	}

}