• JUC 一 CyclicBarrier 与 Semaphore


    java.util.concurrent

    CyclicBarrier简介

    CyclicBarrier:可重用屏障/栅栏

    1. 类似于 CountDownLatch(倒计数闭锁),它能阻塞一组线程直到某个事件的发生。
    2. 与闭锁的关键区别在于,所有的线程必须同时到达屏障位置,才能继续执行。
    3. CountDownLatch 的计数器只能使用一次,而 CyclicBarrier 的计数器可以使用 reset() 方法重置
    4. CountDownLatch 采用减计数方式,CyclicBarrier 采用加计数方式

    CyclicBarrier源码

    构造函数:
    
        //线程到达屏障时,优先执行 barrierAction
        public CyclicBarrier(int parties, Runnable barrierAction) {
            if (parties <= 0) throw new IllegalArgumentException();
            this.parties = parties;
            this.count = parties;
            this.barrierCommand = barrierAction;
        }
    
        public CyclicBarrier(int parties) {
            this(parties, null);
        }
    
    
    await(),await(long timeout, TimeUnit unit) :
        方法的线程告诉 CyclicBarrier 自己已经到达屏障,然后当前线程被阻塞,直到:
    
            1,最后一个线程到达
            2,其他线程中断了当前线程.
            3,其它线程中断了其它等待的线程.
            4,在barrier上面等待的线程发生超时.
            5,其它线程调用了barrier上面的reset方法.
    
    reset()(用于重复利用CyclicBarrier):
        将barrier状态重置。如果此时有线程在barrier处等待,它们会抛出BrokenBarrierException并返回,且这些线程停止等待,继续执行。
    
        public void reset() {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                breakBarrier();   // break the current generation
                nextGeneration(); // start a new generation
            } finally {
                lock.unlock();
            }
        }
    

    CyclicBarrier示例

    public class CyclicBarrierTest {
    
        // 自定义工作线程
        private static class Worker extends Thread {
            private CyclicBarrier cyclicBarrier;
            
            public Worker(CyclicBarrier cyclicBarrier) {
                this.cyclicBarrier = cyclicBarrier;
            }
            
            @Override
            public void run() {
                try {
                    //线程创建后等待,直到有三个线程才执行后续操作
                    cyclicBarrier.await();
    
                    // 工作线程开始处理,这里用Thread.sleep()来模拟业务处理
                    System.out.println(Thread.currentThread().getName() + "执行任务!");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
     
        public static void main(String[] args) {
            //三个线程出现才执行
            CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
            
            for (int i = 0; i < 3; i++) {
                Worker worker = new Worker(cyclicBarrier);
                worker.start();
            }
        }
    }
    

    Semaphore简介

    限制可以访问某些资源的线程数量,例如通过 Semaphore 限流。

    主要方法:
    
    Semaphore(int permits):
        构造方法,创建具有给定许可数的计数信号量并设置为非公平信号量。
    
    Semaphore(int permits,boolean fair):
        构造方法,当fair等于true时,创建具有给定许可数的计数信号量并设置为公平信号量。
    
    void acquire():
        从此信号量获取一个许可前线程将一直阻塞。相当于一辆车占了一个车位。
    
    void acquire(int n):
        从此信号量获取给定数目许可,在提供这些许可前一直将线程阻塞。比如n=2,就相当于一辆车占了两个车位。
    
    void release():
        释放一个许可,将其返回给信号量。就如同车开走返回一个车位。
    
    void release(int n):
        释放n个许可。
    
    int availablePermits():
        当前可用的许可数
    

    Semaphore示例(可以实现单例模式)

    public class SemaphoreDemo {
    	private static final Semaphore semaphore=new Semaphore(3);
    	private static final ThreadPoolExecutor threadPool=new ThreadPoolExecutor(5,10,60,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
    	
    	private static class ThreadDemo extends Thread {
    
    		public void run() {
    			try {
    				//占位(如果许可数达到最大活动数,那么调用acquire()之后,便进入等待队列,等待已获得许可的线程释放许可)
    				semaphore.acquire();
    				//执行任务
    				Thread.sleep(1000);
    				//归还
    				semaphore.release();
    			}
    			catch(InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    
    	public static void main(String[] args) {
    		for(int i=0;i<7;i++) {
    			Thread t1=new ThreadDemo();
    			threadPool.execute(t1);
    		}
    	}
    }
    
    
    /**
     * 使用Semaphore为容器设置边界
     */
    public class BoundHashSet<T> {
    
        public static void main(String[] args) throws InterruptedException {
            BoundHashSet<Integer> set = new BoundHashSet<>();
    
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 15; i++) {
                        try {
                            set.add(i);
                            System.out.println("加入:" + i);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
    
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 10; i++) {
                        System.out.println("移除:" + i);
                        set.remove(i);
                    }
                }
            });
    
            t1.start();
            Thread.sleep(1000);
            t2.start();
        }
    
        private Set<T> set = new ConcurrentSkipListSet<>();
        private Semaphore sem = new Semaphore(10);
    
        public boolean add(T a) throws InterruptedException {
            sem.acquire();
            boolean flag = false;
            try {
                flag = set.add(a);
                return flag;
            } finally {
                if (!flag) {
                    sem.release();
                }
            }
        }
    
        public boolean remove(T a) {
            boolean remove = set.remove(a);
            if (remove) {
                sem.release();
            }
            return remove;
        }
    }
    
  • 相关阅读:
    linq join 左连接 leftjoin 多个on条件 where 条件
    mongodb 学习1
    Couchbase 如何设置密码;bucketPassword设置密码
    js获取网页的url文件名( 例如index.aspx),js获取url的参数(例如获取 ?cid=joeylee的值),给jquery拓展方法
    一个怪异的问题,时间序列化返回的问题
    jQuery 效果
    js对象的创建,拓展方法的创建
    js方法传入对象;js方法传入方法;js方法回调 callback
    js作为参数,并且返回值;js的回调模式 callback
    Connection to Oracle failed. [66000][12505] Listener refused the connection with the following error: ORA-12505, TNS:listener does not currently know of SID given in connect descriptor .
  • 原文地址:https://www.cnblogs.com/loveer/p/11514641.html
Copyright © 2020-2023  润新知