Difference Between Condition signal and signalAll in Java - Java 147

Difference Between Condition signal and signalAll in Java – Java 147

Difference Between Condition signal and signalAll in Java

使用條件等待和信號,也就是取得一個 lock 鎖後,調用 await 方法,進入等待的所有執行緒,有兩種方法可以通知等待執行緒,一個是 signal 隨機喚醒一個正在等待該對象鎖的執行緒,另一個是 signalAll 喚醒所有正在等待該對象鎖的執行緒, Condition signal and signalAll Methods in Java 這表示一旦讓該執行緒暫停執行並且釋放鎖,其他執行緒就可以取得該鎖,喚醒該執行緒,繼續執行符合條件的任務,本篇增加了範例,並透過單元測試來驗證產出結果。

檔案目錄

./
   +- src
       +- test
       |   +- org
       |       +- ruoxue
       |           +- java_147
       |               +- synchronization
       |                   +- reentrantlock
       |                       +- DifferenceConditionSignalSignalAllTest.java   

單元測試

Java Condition signal signalAll Methods 提供執行緒條件暫停、條件喚醒等操作。

signal

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

	@Test
	public void signal() {
		Lock lock = new ReentrantLock();
		Condition condition = lock.newCondition();
		List<Thread> threads = Stream.generate(() -> new Thread(() -> {
			try {
				lock.lock();
				try {
					System.out.println(String.format("T[%d] waiting", Thread.currentThread().getId()));
					condition.await();
					System.out.println(String.format("T[%d] finished", Thread.currentThread().getId()));
				} finally {
					lock.unlock();
				}
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		})).limit(3).collect(Collectors.toList());
		threads.forEach(e -> e.start());

		try {
			TimeUnit.SECONDS.sleep(3);
			lock.lock();
			try {
				System.out.println(String.format("T[%d] signal", Thread.currentThread().getId()));
				condition.signal();
				System.out.println(String.format("T[%d] finished", Thread.currentThread().getId()));
			} finally {
				lock.unlock();
			}
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
	}
T[11] waiting
T[12] waiting
T[13] waiting
T[1] signal
T[1] finished
T[11] finished

signalAll

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

	@Test
	public void signalAll() {
		Lock lock = new ReentrantLock();
		Condition condition = lock.newCondition();
		List<Thread> threads = Stream.generate(() -> new Thread(() -> {
			try {
				lock.lock();
				try {
					System.out.println(String.format("T[%d] waiting", Thread.currentThread().getId()));
					condition.await();
					System.out.println(String.format("T[%d] finished", Thread.currentThread().getId()));
				} finally {
					lock.unlock();
				}
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		})).limit(3).collect(Collectors.toList());
		threads.forEach(e -> e.start());

		try {
			TimeUnit.SECONDS.sleep(3);
			lock.lock();
			try {
				System.out.println(String.format("T[%d] signalAll", Thread.currentThread().getId()));
				condition.signalAll();
				System.out.println(String.format("T[%d] finished", Thread.currentThread().getId()));
			} finally {
				lock.unlock();
			}
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
	}	
T[11] waiting
T[12] waiting
T[13] waiting
T[1] signalAll
T[1] finished
T[11] finished
T[12] finished
T[13] finished

DifferenceConditionSignalSignalAllTest.java

Condition signal signalAll Java 新增單元測試,驗證 Condition signal and signalAll Methods in Java 是否符合預期。

package org.ruoxue.java_147.synchronization.reentrantlock;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.Test;

public class DifferenceConditionSignalSignalAllTest {

	@Test
	public void signal() {
		Lock lock = new ReentrantLock();
		Condition condition = lock.newCondition();
		List<Thread> threads = Stream.generate(() -> new Thread(() -> {
			try {
				lock.lock();
				try {
					System.out.println(String.format("T[%d] waiting", Thread.currentThread().getId()));
					condition.await();
					System.out.println(String.format("T[%d] finished", Thread.currentThread().getId()));
				} finally {
					lock.unlock();
				}
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		})).limit(3).collect(Collectors.toList());
		threads.forEach(e -> e.start());

		try {
			TimeUnit.SECONDS.sleep(3);
			lock.lock();
			try {
				System.out.println(String.format("T[%d] signal", Thread.currentThread().getId()));
				condition.signal();
				System.out.println(String.format("T[%d] finished", Thread.currentThread().getId()));
			} finally {
				lock.unlock();
			}
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
	}

	@Test
	public void signalAll() {
		Lock lock = new ReentrantLock();
		Condition condition = lock.newCondition();
		List<Thread> threads = Stream.generate(() -> new Thread(() -> {
			try {
				lock.lock();
				try {
					System.out.println(String.format("T[%d] waiting", Thread.currentThread().getId()));
					condition.await();
					System.out.println(String.format("T[%d] finished", Thread.currentThread().getId()));
				} finally {
					lock.unlock();
				}
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		})).limit(3).collect(Collectors.toList());
		threads.forEach(e -> e.start());

		try {
			TimeUnit.SECONDS.sleep(3);
			lock.lock();
			try {
				System.out.println(String.format("T[%d] signalAll", Thread.currentThread().getId()));
				condition.signalAll();
				System.out.println(String.format("T[%d] finished", Thread.currentThread().getId()));
			} finally {
				lock.unlock();
			}
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
	}
}

心得分享

Java Condition signal signalAll with Examples 在互斥鎖的情況下,執行緒可能會取得獨占鎖,當發現不具備繼續執行的所需條件時,該執行緒會釋放鎖,並將其狀態改變為等待狀態,直到滿足必要的條件為止,這表示另一條執行緒,稍後將會向當前等待的執行緒發出信號,調用 signal 或 signalAll 方法,以通知其他等待的單一或多個執行緒,重新取得鎖,並檢查是否已經滿足執行的必要條件, Condition signal signalAll Java 提供這兩個方法的應用與場景。

發佈留言