zoukankan      html  css  js  c++  java
  • 并发工具类

    CountDownLatch

      CountDownLatch是一个同步计数器,初始化的时候传入需要计数的线程等待数,可以是需要等待执行完成的线程数,或者大于;

      作用:用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。是一组线程等待其他的线程完成工作以后在执行,相当于加强版join;

      await():阻塞当前线程,等待其他线程执行完成,直达计数器计数值减到0;

      countDown():负责计算器的减一;

    public class CountDownLatchTest {
        public static void main(String[] args) throws InterruptedException {
            System.out.println("等待子线程执行完毕...");
            final CountDownLatch countDownLatch = new CountDownLatch(2);
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    System.out.println("子线程," + Thread.currentThread().getName() + "开始执行...");
                    countDownLatch.countDown();// 每次减去1
                    System.out.println("子线程," + Thread.currentThread().getName() + "结束执行...");
                }
            }).start();
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    System.out.println("子线程," + Thread.currentThread().getName() + "开始执行...");
                    countDownLatch.countDown();
                    System.out.println("子线程," + Thread.currentThread().getName() + "结束执行...");
                }
            }).start();
    
            countDownLatch.await();// 调用当前方法主线程阻塞  countDown结果为0, 阻塞变为运行状态
            System.out.println("两个子线程执行完毕....");
            System.out.println("继续主线程执行..");
        }
    }

    控制台效果

    CyclicBarrier

      CyclicBarrier字面意思是栅栏,是多线程中一个重要的类,主要用于线程内部之间的线程的相互等待问题,初始化的时候传入需要等待的线程数;

      作用:让一组线程达到某一个屏障被阻塞,一直到组内最后一个线程达到屏障时,屏障开放,所有被阻塞的线程才会继续运行;

      CyclicBarrier(int parties):初始化定义需要等待的线程数parties;

      CyclicBarrier(int parties,Runnable barrierAction):当屏障开放的时候,线程barrierAction的任务会执行;

    public class CyclicBarrierTest extends Thread{
    
        private CyclicBarrier cyclicBarrier;
    
        public CyclicBarrierTest(CyclicBarrier cyclicBarrier){
            this.cyclicBarrier=cyclicBarrier;
        }
    
        @Override
        public void run() {
            System.out.println("线程" + Thread.currentThread().getName() + ",正在写入数据");
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                // TODO: handle exception
            }
            System.out.println("线程" + Thread.currentThread().getName() + ",写入数据成功.....");
    
            try {
                cyclicBarrier.await();
            } catch (Exception e) {
            }
            System.out.println("所有线程执行完毕..........");
        }
    
    }
    
    class Test1 {
    
        public static void main(String[] args) {
            CyclicBarrier cyclicBarrier=new CyclicBarrier(5);
            for (int i = 0; i < 5; i++) {
                CyclicBarrierTest cyclicBarrierTest = new CyclicBarrierTest(cyclicBarrier);
                cyclicBarrierTest.start();
            }
        }
    }

    控制台效果

    CountDownLatch和CyclicBarrier的区别:

      1、CountDownLatch放行由第三者控制,CyclicBarrier放行由一组线程本身控制;

      2、CountDownLatch放行条件>=线程数,CyclicBarrier放行条件=线程数;

      3、CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程;

      4、CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置,所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让我们重新执行一次;

    Semaphore

      Semaphore有名信号量,是操作系统中的一个概念,在java并发编程中,信号量控制的是线程并发的数量;

      作用:Semaphore管理一系列许可证。每个acquire方法阻塞,直到有一个许可证可以获得然后拿走一个许可证;每个release方法增加一个许可证,这可能会释放一个阻塞的acquire方法。然而,其实并没有实际的许可证这个对象,Semaphore只是维持一个可获得许可证的数量,主要控制同时访问某个特定资源的线程数量,多用在流量控制;

      注意:其他Semaphore的底层显示就是基于AQS的共享锁实现的

      如果一个线程要访问共享资源,必须先获得信号量,如果信号量的计数器值大于1,意味着有共享资源可以访问,则使其计数器值减去1,在访问共享资源。如果计数器值为0,线程进入休眠。当某个线程使用完共享资源后,释放信号量,并将信号量内部的计数器加1,之间进入休眠的线程将被唤醒并再次试图获取信号量;

    public class SemaphoreDemo implements Runnable {
        private String name;
        private Semaphore wc;
    
        public SemaphoreDemo(String name, Semaphore wc) {
            this.name = name;
            this.wc = wc;
        }
    
        @Override
        public void run() {
            try {
                //剩下的资源
                int availablePermits = wc.availablePermits();
                if (availablePermits>0){
                    System.out.println(name+"有了有了......");
                }else{
                    System.out.println(name+"没了没了......");
                }
                //申请,如果资源达到3次,就等待
                wc.acquire();
                System.out.println(name+"到了到了......");
                Thread.sleep(new Random().nextInt(1000));   //模拟过程的时间
                System.out.println(name+"结束了......");
                wc.release();   //释放资源
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
    // 一个厕所只有3个坑位,但是有10个人来上厕所,那怎么办?假设10的人的编号分别为1-10,并且1号先到厕所,10号最后到厕所。
          那么1-3号来的时候必然有可用坑位,顺利如厕,4号来的时候需要看看前面3人是否有人出来了,如果有人出来,进去,否则等待。同样的道理,
          4-10号也需要等待正在上厕所的人出来后才能进去,并且谁先进去这得看等待的人是否有素质,是否能遵守先来先上的规则。
            Semaphore semaphore=new Semaphore(3);
            for (int i=1;i<=10;i++){
                SemaphoreDemo parent=new SemaphoreDemo(""+i+"个人",semaphore);
                new Thread(parent).start();
            }
        }
    }

    控制台效果

    Exchanger

      Exchanger类似于一个交换器,可以对元素进行配对和交换的线程的同步点,用于两个线程间的数据交换;

      具体来说,Exchanger类允许在两个线程之间定义同步点。当两个线程都到达同步点时,它们交换数据结构,因此第一个线程的数据结构进行第二个线程中,第二个线程的数据结构进入到第一个线程中;

      就像两个线程各个交换自己的数据;

    public class ExchangerTest {
        private static String str1="资源1";
        private static String str2="资源2";
        //构建资源交换对象
        private static Exchanger<String> stringExchanger=new Exchanger<>();
        public static void main(String[] args) {
            //第一个线程
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"初始占用资源:"+str1);
                //资源交换,将资源交给其他线程和获取到其他线程交换过来的资源
                try {
                    String newStr = stringExchanger.exchange(str1);
                    System.out.println(Thread.currentThread().getName()+"交换资源:"+newStr);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
    
            //第二个线程
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"初始占用资源:"+str2);
                //资源交换,将资源交给其他线程和获取到其他线程交换过来的资源
                try {
                    String newStr = stringExchanger.exchange(str2);
                    System.out.println(Thread.currentThread().getName()+"交换资源:"+newStr);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    控制台效果

  • 相关阅读:
    1014 Waiting in Line (30)(30 point(s))
    1013 Battle Over Cities (25)(25 point(s))
    1012 The Best Rank (25)(25 point(s))
    1011 World Cup Betting (20)(20 point(s))
    1010 Radix (25)(25 point(s))
    1009 Product of Polynomials (25)(25 point(s))
    1008 Elevator (20)(20 point(s))
    1007 Maximum Subsequence Sum (25)(25 point(s))
    1006 Sign In and Sign Out (25)(25 point(s))
    1005 Spell It Right (20)(20 point(s))
  • 原文地址:https://www.cnblogs.com/dabrk/p/12526327.html
Copyright © 2011-2022 走看看