Tutorial of using notifyAll() method in Java multithreading

Introduction

This article will undertake the "Java multi-threaded wait() and notify() series of methods using tutorials" , combined with code examples, supplementary explanations of notifyAll()the functions of the methods and the points that need to be paid attention to when using them.

1. Definition of notifyAll() method in JDK

notifyAll()唤醒正在等待此对象监视器锁的所有线程。

Notice:

The meaning in 1. notifyAll()is Allthat all threads, not all locks, can only wake up all threads waiting for the same lock (call wait() method to wait), which must be noted.

2. notifyAll()Must be executed when the current thread owns the monitor lock, otherwise an exception will be thrown IllegalMonitorStateException. It means that this method must be called in a synchronized code block, otherwise it may be executed without the lock, resulting in a program exception. wait()And notify()series methods are designed this way to prevent deadlocks or perpetual waits from occurring.

3. The notifyAll()method can be called by any object, and this method cannot be overridden because it is finaldecorated.

4. notifyAll()Only one lock can be released. It is important to list this article separately.

5. notifyAll()After execution, only one thread can get the lock, and other threads that do not get the lock will continue to wait in the waiting state.

2. Explain a standard notifyAll() method using code

Code logic description:

  1. Threads thread0and thread1common contention objectobject lock, and call their respective wait()methods to wait.
  2. The thread thread2is responsible for notifyAll()waking up the thread.
public class ThreadWaitAndNotifyAll implements Runnable {

	// 模拟多个线程的共享变量
	private static Object object = new Object();

	@Override
	public void run() {
		synchronized (object) {
			System.out.println("线程" + Thread.currentThread().getName() + "获得锁,进入等待状态");
			try {
				object.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("线程" + Thread.currentThread().getName() + "执行最后部分结束");
		}
	}

	public static void main(String[] args) {
		ThreadWaitAndNotifyAll runnable = new ThreadWaitAndNotifyAll();
		Thread thread0 = new Thread(runnable);
		Thread thread1 = new Thread(runnable);
		Thread thread2 = new Thread(new Runnable() {
			@Override
			public void run() {
				synchronized (object) {
					System.out.println("线程" + Thread.currentThread().getName() + "获得锁,开始通知唤醒所有线程");
					// 唤醒其他线程
					object.notifyAll();
					// 调用完notifyAll()方法后,同步代码块中的其他代码,必须执行完后才能将对象锁释放,而不是调用了notifyAll()方法后立即释放。
					System.out.println("线程" + Thread.currentThread().getName() + "执行结束");
				}
			}
		});
		// 每次运行,线程0和线程1的顺序可能会不同,执行顺序由CPU决定
		thread0.start();
		thread1.start();
		try {
			// 加一个延时,让线程2一定在线程0和1之后执行,否则线程2中的notifyAll方法将无效
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		thread2.start();
	}
}

Results of the:

线程Thread-0获得锁,进入等待状态
线程Thread-1获得锁,进入等待状态
线程Thread-2获得锁,开始通知唤醒所有线程
线程Thread-2执行结束
线程Thread-1执行最后部分结束
线程Thread-0执行最后部分结束

Execute the result analysis:

  1. thread0And thread1after startup, each will execute its own code, and after the wait()method is executed, it will enter the waiting state.
  2. thread2Before starting, the sleepdelay is deliberately increased to ensure that the execution order is guaranteed to run after the first two threads.
  3. thread2After the notifyAll()method is executed and the synchronizedrest of the code block is executed, the CPU will objectrandomly assign the object lock to thread0or thread1(only one of the two can be selected).
  4. If thread1the lock is obtained, it will continue to execute the wait()code after its method, and the CPU will not assign the object objectlock to the waiting thread until the content of the synchronized code block is fully executed thread0.
  5. thread0After getting so, it will continue to execute from the method, and the lock wait()on the object will not be released until the end of the synchronized code block .object

Note: After the method is called notifyAll(), other codes in the synchronized code block must be executed before the object lock can be released, not notifyAll()immediately after the method is called.

3. Very important hidden knowledge points about notifyAll()

In java, after the thread of Thread class executes the run() method, it will automatically execute the notifyAll() method.

This detail is hidden in Java's Native methods, so it is generally not discovered. We observe the C/C++ source code as follows:

oid JavaThread::exit(booldestory_vm, ExitTypeexit_type);
static void ensure_join(JavaThread*thread) {
	Handle threadObj(thread, thread -> threadObj());
	ObjectLocker lock(threadObj, thread);
	thread -> clear_pending_exception();
	java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
	java_lang_Thread::set_thread(threadObj(), NULL);
     //下行执行了notifyAll()操作
	lock.notify_all(thread);
	thread -> clear_pending_exception();
}

Among them ensure_join, the join() method is executed. When the method execution ends, this line of code lock.notify_all(thread);means that notifyAll()all waiting threads are woken up. So be careful when using threads.

Summarize

After explaining the notifyAll()usage of the methods in this article, the notifyseries of methods have been explained. In the next article, we will implement several important and specific scenarios to use these methods to do some things and see how these methods are often used. where. If you like this article, please continue to pay attention to follow-up articles as well as bookmark and like.

Guess you like

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