Difference Between notify and notifyAll in Java - Java 147

Difference Between notify and notifyAll in Java – Java 147

Difference Between notify and notifyAll in Java

對於在此物件的監視器上,也就是取得一個 lock 鎖後,調用 wait 方法,進入等待的所有執行緒,有兩種方法可以通知等待執行緒,一個是 notify 隨機喚醒一個正在等待該對象鎖的執行緒,另一個是 notifyAll 喚醒所有正在等待該對象鎖的執行緒, notify and notifyall Methods in Java ,提供這兩種方法的應用方式,本篇增加了範例,並透過單元測試來驗證產出結果。

檔案目錄

./
   +- src
       +- test
       |   +- org
       |       +- ruoxue
       |           +- java_147
       |               +- multithreading
       |                   +- thread
       |                       +- DifferenceNotifyNotifyAllTest.java   

單元測試

Java notify notifyall Methods 提供執行緒暫停、喚醒等操作。

notifyz

Java notify notifyall Methods 建立 1 個物件做為鎖,建立 3 條執行緒,先取得 lock 後,調用 wait 暫停當前的執行緒,然後由主執行緒調用 notify ,隨機喚醒一個正在等待該對象鎖的執行緒。

	@Test
	public void notifyz() {
		Object lock = new Object();
		List<Thread> threads = Stream.generate(() -> new Thread(() -> {
			try {
				synchronized (lock) {
					System.out.println("T[" + Thread.currentThread().getId() + "] waiting");
					lock.wait();
				}
				System.out.println("T[" + Thread.currentThread().getId() + "] finished");
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		})).limit(3).collect(Collectors.toList());
		threads.forEach(e -> e.start());

		try {
			TimeUnit.SECONDS.sleep(3);
			synchronized (lock) {
				System.out.println("T[" + Thread.currentThread().getId() + "] notify");
				lock.notify();
			}
			TimeUnit.SECONDS.sleep(3);
			System.out.println("T[" + Thread.currentThread().getId() + "] finished");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
T[11] waiting
T[13] waiting
T[12] waiting
T[1] notify
T[11] finished

notifyAllz

Java notify notifyall Methods 建立 1 個物件做為鎖,建立 3 條執行緒,先取得 lock 後,調用 wait 暫停當前的執行緒,然後由主執行緒調用 notifyAll ,喚醒所有正在等待該對象鎖的執行緒,重新參與競爭。

	@Test
	public void notifyAllz() {
		final Object lock = new Object();
		List<Thread> threads = Stream.generate(() -> new Thread(() -> {
			try {
				synchronized (lock) {
					System.out.println("T[" + Thread.currentThread().getId() + "] waiting");
					lock.wait();
				}
				System.out.println("T[" + Thread.currentThread().getId() + "] finished");
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		})).limit(3).collect(Collectors.toList());
		threads.forEach(e -> e.start());

		try {
			TimeUnit.SECONDS.sleep(3);
			synchronized (lock) {
				System.out.println("T[" + Thread.currentThread().getId() + "] notifyAll");
				lock.notifyAll();
			}
			TimeUnit.SECONDS.sleep(3);
			System.out.println("T[" + Thread.currentThread().getId() + "] finished");
			threads.forEach(e -> assertFalse(e.isAlive()));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
T[11] waiting
T[12] waiting
T[13] waiting
T[1] notifyAll
T[13] finished
T[12] finished
T[11] finished
T[1] finished

DifferenceNotifyNotifyAllTest.java

notify notifyall Java 新增單元測試,驗證是否符合預期。

package org.ruoxue.java_147.synchronization.thread;

import static org.junit.Assert.assertFalse;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.Test;

public class DifferenceNotifyNotifyAllTest {

	@Test
	public void notifyz() {
		Object lock = new Object();
		List<Thread> threads = Stream.generate(() -> new Thread(() -> {
			try {
				synchronized (lock) {
					System.out.println("T[" + Thread.currentThread().getId() + "] waiting");
					lock.wait();
				}
				System.out.println("T[" + Thread.currentThread().getId() + "] finished");
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		})).limit(3).collect(Collectors.toList());
		threads.forEach(e -> e.start());

		try {
			TimeUnit.SECONDS.sleep(3);
			synchronized (lock) {
				System.out.println("T[" + Thread.currentThread().getId() + "] notify");
				lock.notify();
			}
			TimeUnit.SECONDS.sleep(3);
			System.out.println("T[" + Thread.currentThread().getId() + "] finished");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	@Test
	public void notifyAllz() {
		final Object lock = new Object();
		List<Thread> threads = Stream.generate(() -> new Thread(() -> {
			try {
				synchronized (lock) {
					System.out.println("T[" + Thread.currentThread().getId() + "] waiting");
					lock.wait();
				}
				System.out.println("T[" + Thread.currentThread().getId() + "] finished");
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		})).limit(3).collect(Collectors.toList());
		threads.forEach(e -> e.start());

		try {
			TimeUnit.SECONDS.sleep(3);
			synchronized (lock) {
				System.out.println("T[" + Thread.currentThread().getId() + "] notifyAll");
				lock.notifyAll();
			}
			TimeUnit.SECONDS.sleep(3);
			System.out.println("T[" + Thread.currentThread().getId() + "] finished");
			threads.forEach(e -> assertFalse(e.isAlive()));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

心得分享

Java notify notifyAll with Examples 在互斥鎖的情況下,假設有一個生產者執行緒和一個消費者執行緒,生產者生產的每個數據包都應該由消費者消費,此時調用 notify ,被喚醒的的執行緒便會進入該物件的鎖池中,鎖池中的執行緒會去競爭該物件鎖。也就是說,只有 1 個執行緒會由等待池進入鎖池,另一個案例,假設希望在冗長的過程結束時收到通知,如:嗶聲和螢幕更新,此時該執行緒調用 notifyAll ,以通知其他等待的更新執行緒,將該物件等待池內的所有執行緒移動到鎖池中,等待鎖競爭, notify notifyall Java 提供這兩個方法的應用與場景。

發佈留言