Table of Contents
ToggleDifference 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 提供這兩個方法的應用與場景。