zoukankan      html  css  js  c++  java
  • 线程应用:(八)Semaphere信号灯、CyclicBarrier汇合、CountDownLatch计数器、Exchanger

    一、Semaphere信号灯

      Semaphere与互斥锁的区别:有多个线程时,只有获得互斥锁的那个才能进入,而信号灯是可以同时多个线程一起运行的,信号灯为1时相当于互斥锁。
      等待的线程准备获得信号灯的顺序是随机的,但可以设置先到先得。

      假设有10个线程,但只有3个信号灯,能实现并发访问的线程数只能为3,剩下的7个线程要等待获得信号灯才能运行,代码如下。

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Semaphore;
    
    public class SemaphoreTest {
        public static void main(String[] args) {
            ExecutorService service = Executors.newCachedThreadPool();      //创建缓存线程池
            final Semaphore sp = new Semaphore(3);    //创建信号灯个数为3,为1相当于互斥
            
            for(int i=0;i<10;i++){
                Runnable runnable = new Runnable() {    //创建10个线程,但只有3个信号灯,实际只有3个线程运行
                    @Override
                    public void run() {
                        try {
                            sp.acquire();    //获得信号灯
                            System.out.println(Thread.currentThread().getName()+"进入"+", 并发数:"+(3-sp.availablePermits()));
                            Thread.sleep((long)(Math.random()*10000));
                            System.out.println(Thread.currentThread().getName()+"准备离开"+", 并发数:"+(3-sp.availablePermits()));
                            sp.release();    //释放信号灯,其他线程可进入
                            System.out.println(Thread.currentThread().getName()+"已离开"+", 并发数:"+(3-sp.availablePermits()));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }    
                    }
                };
                service.execute(runnable);    //把任务提交到线程池
            }
        }
    }

    二、CyclicBarrier汇合

      大家彼此等待,先到的会先等待,大家集合好后才开始出发。可以反复使用,await后重新计数。

    import java.util.concurrent.CyclicBarrier;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class CyclicBarrierTest {
        public static void main(String[] args) {
            ExecutorService service = Executors.newCachedThreadPool();
            final CyclicBarrier cb = new CyclicBarrier(3);    //设定3个线程到齐后才继续往下走
            
            for(int i=0;i<3;i++){
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep((long)(Math.random()*10000));
                            System.out.println(Thread.currentThread().getName()+"即将到达集合点1"+", 当前已到:"+(cb.getNumberWaiting()+1));
                            cb.await();    //表示在这里集合,如果没有到齐则等待,到齐了才往下走
                            Thread.sleep((long)(Math.random()*10000));
                            System.out.println(Thread.currentThread().getName()+"即将到达集合点2"+", 当前已到:"+(cb.getNumberWaiting()+1));
                            cb.await();
                            Thread.sleep((long)(Math.random()*10000));
                            System.out.println(Thread.currentThread().getName()+"即将到达集合点3"+", 当前已到:"+(cb.getNumberWaiting()+1));
                            cb.await();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }    
                    }
                };
                service.execute(runnable);    //把任务提交到线程池
            }
        }
    }

    三、CountDownLatch计数器

      类似倒计时计数器,当计数到达0时,才让所有等待者或单个等待者开始执行。

    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class CountDownLatchTest {
        public static void main(String[] args) throws InterruptedException {
            ExecutorService service = Executors.newCachedThreadPool();
            final CountDownLatch oneDown = new CountDownLatch(1);
            final CountDownLatch threeDown = new CountDownLatch(3);
            
            for(int i=0;i<3;i++){
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        try {
                            oneDown.await();  //第二步:3个线程会在这里等,直到oneDown的值减为0,才会接着进行
                            Thread.sleep((long)(Math.random()*10000));
                            threeDown.countDown();    //第三步:每当有线程走到这,threeDown减1
                        } catch (Exception e) {
                            e.printStackTrace();
                        }    
                    }
                };
                service.execute(runnable);
            }
            
            Thread.sleep((long)(Math.random()*10000));
            oneDown.countDown();    //第一步:oneDown先减为0,让上面的3个线程走
            threeDown.await();        //第四步:直到上面3个线程把threeDown减为0才继续通行
            
            service.shutdown();
        }
    }

    四、Exchanger

      可以实现两个线程间的数据交换,两者都到达exchanger.exchange()方法后,才交换数据,然后各自继续进行。

    import java.util.concurrent.Exchanger;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class ExchangerTest {
        public static void main(String[] args) {
            ExecutorService service = Executors.newCachedThreadPool();
            final Exchanger<String> exchanger = new Exchanger<String>();
            
            service.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        String data1 = "AAAAA";
                        System.out.println(Thread.currentThread().getName()+"准备换的数据:"+data1);
                        Thread.sleep((long)(Math.random()*10000));
                        String data2 = exchanger.exchange(data1);    //线程1准备把data1换成data2
                        System.out.println(Thread.currentThread().getName()+"换回的数据:"+data2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                }
            });
            
            service.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        String data1 = "BBBBB";
                        System.out.println(Thread.currentThread().getName()+"准备换的数据:"+data1);
                        Thread.sleep((long)(Math.random()*10000));
                        String data2 = exchanger.exchange(data1);    //线程1准备把data1换成data2
                        System.out.println(Thread.currentThread().getName()+"换回的数据:"+data2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
  • 相关阅读:
    druid的配置
    js学习(五)-全局函数和类内部函数区别
    js学习(四)- prototype原型对象
    js学习(三)-使用大括号({ })语法创建无类型对象
    js学习(一)-动态添加、修改、删除对象的属性和方法
    js学习(一)-对象和函数概念
    js关于函数和对象的概念
    js传递数组到后台
    ubantu一些资料
    fiddler的编程文章
  • 原文地址:https://www.cnblogs.com/zjxiang/p/9432895.html
Copyright © 2011-2022 走看看