Difference Between Condition await and signal in Java - Java 147

Difference Between Condition await and signal in Java – Java 147

Difference Between Condition await and signal in Java

兩個執行緒共享一些資源並執行兩個不同的任務,希望執行緒僅在另一個執行緒完成某些任務 B 後才執行某些任務 A ,簡而言之,該執行緒必須檢查是否滿足某些條件才能執行任務 A , Difference Between Condition signal and await in Java 調用 await 方法時,調用執行緒停止執行,直到 signal 或 signalAll 方法被其他某個執行緒調用, Difference Between Condition await and signal Methods in Java 本篇增加了範例,並透過單元測試來驗證產出結果。

檔案目錄

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

單元測試

Difference Between Condition await and signal 提供執行緒暫停、喚醒、拋出例外等操作。

worker

Difference Between Condition await and signal 建立 1 個物件,提供儲存跟讀取 2 個方法,當儲存執行緒調用 put 方法耗時 3 秒,完成任務時,會喚醒另一條讀取執行緒,因調用 take 方法而被暫停的執行緒, Difference Between Condition signal and await 建立 2 條執行緒,分別調用 1 個物件儲存跟讀取的方法。

	protected class Worker {

		private volatile boolean done = false;
		private final Lock lock = new ReentrantLock();
		private Condition condition = lock.newCondition();

		public Worker() {
		}

		public void put() throws InterruptedException {
			lock.lock();
			try {
				TimeUnit.SECONDS.sleep(3);
				System.out.println(String.format("T[%d] put finished", Thread.currentThread().getId()));
				done = true;
				condition.signal();
			} finally {
				lock.unlock();
			}
		}

		public boolean take() throws InterruptedException {
			lock.lock();
			try {
				while (!done) {
					System.out.println(String.format("T[%d] take waiting", Thread.currentThread().getId()));
					condition.await();
				}
			} finally {
				lock.unlock();
			}
			return done;
		}
	}

	@Test
	public void worker() {
		Worker worker = new Worker();
		Thread threadA = new Thread(() -> {
			String id = "A";
			try {
				System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
				worker.put();
				System.out.println(String.format("T[%d] worker: %s finished", Thread.currentThread().getId(), id));
				worker.put();
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		});

		Thread threadB = new Thread(() -> {
			String id = "B";
			try {
				System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
				boolean done = worker.take();
				System.out.println(String.format("T[%d] worker: %s finished, result: %b",
						Thread.currentThread().getId(), id, done));
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		});

		threadB.start();
		threadA.start();

		try {
			threadA.join();
			threadB.join();
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
	}
T[12] worker: B ready
T[12] take waiting
T[11] worker: A ready
T[11] put finished
T[11] worker: A finished
T[12] worker: B finished, result: true

interruptWorker

Difference Between Condition await and signal 建立 1 個物件,提供儲存跟讀取 2 個方法,當儲存執行緒,調用 put 方法耗時 3 秒,完成任務時,沒有喚醒另一條讀取執行緒,因調用 take 方法而被暫停的執行緒, Difference Between Condition signal and await 建立 2 條執行緒,分別調用 1 個物件儲存跟讀取的方法,主執行緒等待 2 秒後,調用 interrupt 中斷讀取執行緒。

	protected class InterruptWorker {

		private volatile boolean done = false;
		private final Lock lock = new ReentrantLock();
		private Condition condition = lock.newCondition();

		public InterruptWorker() {
		}

		public void put() throws InterruptedException {
			lock.lock();
			try {
				TimeUnit.SECONDS.sleep(3);
				System.out.println(String.format("T[%d] put finished", Thread.currentThread().getId()));
				done = true;
				// condition.signal();
			} finally {
				lock.unlock();
			}
		}

		public boolean take() throws InterruptedException {
			lock.lock();
			try {
				while (!done) {
					System.out.println(String.format("T[%d] take waiting", Thread.currentThread().getId()));
					condition.await();
				}
			} finally

			{
				lock.unlock();
			}
			System.out.println(lock);
			return done;
		}

	}

	@Test
	public void interruptWorker() {
		InterruptWorker worker = new InterruptWorker();
		Thread threadA = new Thread(() -> {
			String id = "A";
			try {
				System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
				worker.put();
				System.out.println(String.format("T[%d] worker: %s finished", Thread.currentThread().getId(), id));

			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		});

		Thread threadB = new Thread(() -> {
			String id = "B";
			try {
				System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
				boolean done = worker.take();
				System.out.println(String.format("T[%d] worker: %s finished, result: %b",
						Thread.currentThread().getId(), id, done));
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		});

		threadB.start();
		threadA.start();

		try {
			threadA.join();
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}

		long startTime = System.currentTimeMillis();
		while (true) {
			if (System.currentTimeMillis() - startTime > 1000) {
				threadB.interrupt();
				break;
			}
		}
	}
T[12] worker: B ready
T[12] take waiting
T[11] worker: A ready
T[11] put finished
T[11] worker: A finished
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:2014)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2048)
	at org.ruoxue.java_147.synchronization.DifferenceConditionAwaitSignalTest$InterruptWorker.take(DifferenceConditionAwaitSignalTest.java:110)
	at org.ruoxue.java_147.synchronization.DifferenceConditionAwaitSignalTest.lambda$3(DifferenceConditionAwaitSignalTest.java:141)
	at java.lang.Thread.run(Thread.java:750)

DifferenceConditionAwaitSignalTest.java

Difference Between Condition signal and await 新增單元測試,驗證是否符合預期。

package org.ruoxue.java_147.synchronization.reentrantlock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.junit.Test;

public class DifferenceConditionAwaitSignalTest {

	protected class Worker {

		private volatile boolean done = false;
		private final Lock lock = new ReentrantLock();
		private Condition condition = lock.newCondition();

		public Worker() {
		}

		public void put() throws InterruptedException {
			lock.lock();
			try {
				TimeUnit.SECONDS.sleep(3);
				System.out.println(String.format("T[%d] put finished", Thread.currentThread().getId()));
				done = true;
				condition.signal();
			} finally {
				lock.unlock();
			}
		}

		public boolean take() throws InterruptedException {
			lock.lock();
			try {
				while (!done) {
					System.out.println(String.format("T[%d] take waiting", Thread.currentThread().getId()));
					condition.await();
				}
			} finally {
				lock.unlock();
			}
			return done;
		}
	}

	@Test
	public void worker() {
		Worker worker = new Worker();
		Thread threadA = new Thread(() -> {
			String id = "A";
			try {
				System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
				worker.put();
				System.out.println(String.format("T[%d] worker: %s finished", Thread.currentThread().getId(), id));
				worker.put();
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		});

		Thread threadB = new Thread(() -> {
			String id = "B";
			try {
				System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
				boolean done = worker.take();
				System.out.println(String.format("T[%d] worker: %s finished, result: %b",
						Thread.currentThread().getId(), id, done));
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		});

		threadB.start();
		threadA.start();

		try {
			threadA.join();
			threadB.join();
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
	}

	protected class InterruptWorker {

		private volatile boolean done = false;
		private final Lock lock = new ReentrantLock();
		private Condition condition = lock.newCondition();

		public InterruptWorker() {
		}

		public void put() throws InterruptedException {
			lock.lock();
			try {
				TimeUnit.SECONDS.sleep(3);
				System.out.println(String.format("T[%d] put finished", Thread.currentThread().getId()));
				done = true;
				// condition.signal();
			} finally {
				lock.unlock();
			}
		}

		public boolean take() throws InterruptedException {
			lock.lock();
			try {
				while (!done) {
					System.out.println(String.format("T[%d] take waiting", Thread.currentThread().getId()));
					condition.await();
				}
			} finally

			{
				lock.unlock();
			}
			System.out.println(lock);
			return done;
		}

	}

	@Test
	public void interruptWorker() {
		InterruptWorker worker = new InterruptWorker();
		Thread threadA = new Thread(() -> {
			String id = "A";
			try {
				System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
				worker.put();
				System.out.println(String.format("T[%d] worker: %s finished", Thread.currentThread().getId(), id));

			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		});

		Thread threadB = new Thread(() -> {
			String id = "B";
			try {
				System.out.println(String.format("T[%d] worker: %s ready", Thread.currentThread().getId(), id));
				boolean done = worker.take();
				System.out.println(String.format("T[%d] worker: %s finished, result: %b",
						Thread.currentThread().getId(), id, done));
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		});

		threadB.start();
		threadA.start();

		try {
			threadA.join();
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}

		long startTime = System.currentTimeMillis();
		while (true) {
			if (System.currentTimeMillis() - startTime > 1000) {
				threadB.interrupt();
				break;
			}
		}
	}
}

心得分享

Difference Between Condition await and signal Methods in Java 執行緒持續檢查是否滿足條件,如果不滿足,會釋放對資源的鎖定並進入等待狀態,另一條執行緒調用 singnal 方法,會喚醒原執行緒,如果滿足條件,原執行緒可以完成工作,否則將再次重複該過程, Difference Between Condition signal and await 提供這兩個方法的區別與使用。

發佈留言