Java Concurrency and Lock Design Implementation Details (10) - Waiting/Notification Mechanism in Java

The wait/notify mechanism in Java is a way to realize inter-thread communication. It is accomplished by methods such as wait/notify/notifyAll. What do these methods mean?

Listed below:

Related methods to wait/notify
method name describe
notify() Notifies a thread waiting on an object to return from the wait() method if the thread acquires the object's lock
notifyAll() Notify all threads waiting on the object, but these threads also need to compete to acquire the object lock
wait() The thread calling this method will enter the WAITING state, and can return from this method only after waiting for notification from another thread or being interrupted. Special attention should be paid to that, when the wait() method is called, the current thread will release the object's lock
wait(long) Timeout and wait for a period of time. The parameter unit here is milliseconds. If the waiting time exceeds the set timeout time and no notification is received, the timeout will be returned.
wait(long,int) For finer-grained control of timeouts, up to nanoseconds

Remarks: Before calling the above method, the object lock must be acquired, otherwise an IlligalMonitorStateException will be thrown.

The waiting notification mechanism means that a thread A releases the object lock it holds and enters the waiting state after calling the wait()/wait(long)/wait(long,int) method, while another thread B acquires the object After the lock, call the notify()/notifyAll() method and release the object lock to notify thread A to continue executing from the wait()/wait(long)/wait(long, int) method. Thread A and thread B themselves are independent, but with the help of the same object lock and wait/notify mechanism to achieve inter-thread communication and interactive work.

Below we implement a simple example based on the wait/notify mechanism.

package com.majing.java.concurrent;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;


public class WaitNotifySample {
	static Object lock = new Object();
	static boolean flag = false;//是否具备执行某块逻辑的条件
	
	public static void main(String[] args) {
		Thread  waitThread = new Thread(new Wait(),"WaitThread");
		waitThread.start();
		Thread  notifyThread = new Thread(new Notify(),"NotifyThread");
		notifyThread.start();
	}
	
	static class Wait implements Runnable{

		@Override
		public void run() {
			synchronized (lock) {
				System.out.println(Thread.currentThread()+" hold the lock at time "+(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
				while(!flag){
					System.out.println(Thread.currentThread()+" flag is false, wait at time "+(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
					try {
						lock.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				//条件满足时,执行业务代码
				System.out.println(Thread.currentThread()+" flag is true, running at time "+(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
			}
		}
		
	}
	
	static class Notify implements Runnable{

		@Override
		public void run() {
			synchronized (lock) {
				System.out.println(Thread.currentThread()+" hold the lock at time "+(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
				System.out.println(Thread.currentThread()+" do some work.");
				System.out.println(Thread.currentThread()+" notify at time "+(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
				lock.notifyAll();//不会释放lock锁
				flag = true;
			}
			try {
				TimeUnit.SECONDS.sleep(2);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (lock) {
				System.out.println(Thread.currentThread()+" hold the lock again and do some other time at time "+(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));
			}
		}
		
	}
	
}

执行效果如下:

Thread[WaitThread,5,main] hold the lock at time 2018-04-21 17:12:01
Thread[WaitThread,5,main] flag is false, wait at time 2018-04-21 17:12:01
Thread[NotifyThread,5,main] hold the lock at time 2018-04-21 17:12:01
Thread[NotifyThread,5,main] do some work.
Thread[NotifyThread,5,main] notify at time 2018-04-21 17:12:01
Thread[WaitThread,5,main] flag is true, running at time 2018-04-21 17:12:01
Thread[NotifyThread,5,main] hold the lock again and do some other time at time 2018-04-21 17:12:03

从上面可以看出,WaitThread线程先执行,但是因为条件未达到,所以在获取到对象锁之后又释放了相应的锁,这时候NotifyThread线程发现可以后去到对象锁,然后便do some work,并且变更了状态位flag,并且在执行完之后通过notifyAll给其他等待在该对象锁上的线程可以去竞争对象锁了,之后WaitThread获取到对象锁并且继续执行,在WaitThread线程执行完之后释放了对象锁,而NotifyThread线程重新获取对象锁然后做了其他的一些工作。

下面附上一张图,可以直观的看出wait/notify机制的原理(参考自:《Java并发编程的艺术》):

在每个对象的监视器锁上面都维护着两个队列,一个是同步队列,一个是等待队列。对于等待队列中的线程只有收到特定的通知信号才能迁移到同步队列。




Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325915273&siteId=291194637