使用 wait 和 notifyAll 来实现可重新关闭的阀门

读《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);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值