线程应用:(八)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();
                }
            }
        });
    }
}

 

posted @ 2018-08-13 20:52  湮天霸神666  阅读(119)  评论(0编辑  收藏  举报