• 同步工具类


    同步工具类可以是任何一个对象,只要它根据其自身的状态来协调线程的控制流。

    阻塞队列

    保存对象的容器, 还能协调生产者和消费者等线程之间的控制流 take和put等方法将阻塞,直到队列达到期望的状态(队列即非空,也非满)。

    闭锁

    相当于一扇门:在闭锁到达结束状态之前,这扇门一直是关闭的,并且没有任何线程能通过,当到达结束状态时,这扇门会打开并允许所有线程通过。

    到达结束状态后,将不会再改变状态,这扇门永远保持打开状态。

    CountDownLatch(倒计数锁存器) 是一种灵活的闭锁实现
    countDown方法递减计数器
    await方法等待计数器达到零,阻塞直到计数器为零或者等待中的线程中断,或者等待超时

    使用场景

    示例:

    public class TestHarness {
    
        public long timeTasks(int nThreads, final Runnable task) throws InterruptedException {
            final CountDownLatch startGate = new CountDownLatch(1);//起始门
            final CountDownLatch endGate = new CountDownLatch(nThreads);//结束门
    
            for (int i = 0; i < nThreads; i++) {
                Thread t = new Thread(){
                    @Override
                    public void run() {
                        try {
                            startGate.await();//一直阻塞直到计数器为零
                            try {
                                task.run();
                            }finally {
                                endGate.countDown();
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };
                t.start();
            }
    
            long start = System.nanoTime();
            startGate.countDown();
            endGate.await();
            long end = System.nanoTime();
            return end - start;
        }
    
    }

    FutureTask

    也可以用作闭锁。

    信号量

    计数信号量用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量。还可以用来实现某种资源池,或者对容器加边界。

    Semaphore中管理者一组虚拟的许可,在执行操作时可以首先获得许可,并在使用以后释放许可,如果没有许可,那么acquire将阻塞直到有许可(或者直到中断或者操作超时)。

    release方法将返回一个许可给信号量,计算信号量的一种简化形式是二值信号量,即初始值为1的Semaphore。二值信号量可以用作互斥体,并具备不可重入的加锁语义:谁拥有这个唯一的许可,谁就拥有了互斥锁。

    Semaphore可以用于实现资源池,例如数据库连接池。

    使用Semaphore为容器设置边界:

    public class BoundedHashSet<T> {
        private final Set<T> set;
        private final Semaphore sem;
    
        public BoundedHashSet(int bound) {
            this.set = Collections.synchronizedSet(new HashSet<T>());
            sem = new Semaphore(bound);
        }
    
        public boolean add(T o) throws InterruptedException{
            sem.acquire();
            boolean wasAdded = false;
            try {
                wasAdded = set.add(o);
                return wasAdded;
            } finally {
                if (!wasAdded)
                    sem.release();
            }
        }
    
        public boolean remove(Object o) {
            boolean wasRemoved = set.remove(o);
            if (wasRemoved){
                System.out.println(Thread.currentThread().getName()+" remove "+o);
                sem.release();
            }
            return wasRemoved;
        }
    
    }
    

    栅栏

    栅栏(Barrier)类似于闭锁,它能阻塞一组线程直到某个事件发生。

    闭锁是一次性对象,一旦进入终止状态,就不能被重置。

    栅栏与闭锁的关键区别在于,所有的线程必须同时到达栅栏位置,才能继续执行。闭锁用于等待事件,而栅栏用于等待其他线程。

    CyclicBarrier可以使一定数量的参与方反复地在栅栏位置汇集,它在并行迭代算法中非常有用:这种算法通常将一个问题拆分成一系列相互独立的子问题。

    当线程到达栅栏位置时将调用await方法,这个方法将阻塞直到所有线程都到达栅栏位置。

  • 相关阅读:
    Ubuntu18.04下更改apt源为阿里云源
    sudo: pip:command not found问题解决
    CentOS8 中文输入法
    PyCharm2019 激活方式
    正则爬取京东商品信息并打包成.exe可执行程序
    学习springcloud bus+springcloud config实现刷新配置
    使用springcloud-config统一管理配置文件
    记录一下今天使用maven构建项目分多个模块时遇到的扫描properties问题
    spring+mybatis+thymeleaf
    回调地狱问题
  • 原文地址:https://www.cnblogs.com/lucare/p/8679145.html
Copyright © 2020-2023  润新知