读《Java并发编程实战》笔记。
实现类:
package com.hyl.learnerconcurrency.practice;
public class ThreadGate {
// 条件谓词:opened-since(n) (isOpen || generation > n)
private boolean isOpen;
private int generation;
public synchronized void close(){
isOpen = false;
}
public synchronized void open(){
++generation;
isOpen = true;
notifyAll();
}
/**
* 阻塞并直到:opened-since(generation on entry)
*
* @throws InterruptedException
*/
public synchronized void await() throws InterruptedException{
int arrivalGeneration = generation;
while (!isOpen && arrivalGeneration == generation){
wait();
}
}
}
在
await
中使用的条件谓词比测试isOpen
复杂得多。
这种条件谓词时是必需的,因为如果当阀门打开时有 N 个线程正在等待它,那么这些线程都应该被允许执行。
然而,如果阀门在打开后又非常快速的关闭了,并且await
方法只检查isOpen
,那么所有线程都可能无法释放:
当所有线程收到通知时,将重新请求锁并退出wait
,而此时的阀门可能已经再次关闭了。
因此,在ThreadGate
中使用了一个更复杂的条件谓词:
每次阀门关闭时,递增一个 “Generation
” 计数器,如果阀门现在是打开的,或者阀门自从该线程到达后就一直是打开的,那么线程就可以通过 await。
测试类:
package com.hyl.learnerconcurrency.practice.test;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import com.hyl.learnerconcurrency.practice.ThreadGate;
public class ThreadGateTest {
public static void main(String[] args) throws InterruptedException {
ThreadGate gate = new ThreadGate();
AtomicLong count = new AtomicLong();
Runnable runnable = ()->{
System.out.println(Thread.currentThread().getName()+":启动");
while (true){
try {
gate.await();
count.incrementAndGet();
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
System.out.println(Thread.currentThread().getName()+": 运行中 -> "+count.get());
}
};
for (int i = 0; i < 10; i++) {
new Thread(runnable).start();
}
TimeUnit.SECONDS.sleep(1);
boolean flag = true;
for (;;){
if (flag){
flag = false;
gate.open();
}else {
flag = true;
gate.close();
}
TimeUnit.SECONDS.sleep(1);
}
}
}