java基础系列(八):Semphore,CountDownLatch和CyclicBarrier的使用

一,Semphore的使用

      信号量主要有两个作用,一个是用于多个共享资源的互斥使用,另一个用于并发线程数控制。

  (1)通过acquire()获取一个信号量,计数器减一,信号量为0,线程进入阻塞等待状态。

  

   (2)通过realease()释放一个信号量,计数器加一,如果有等待的线程则唤醒。

  

   (3)实战

   public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" 获取到了");
                    try {
                        Thread.sleep(2000);
                        System.out.println(Thread.currentThread().getName());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        semaphore.release();
                    }

                }
            }).start();
        }
}
//运行结果

Thread-0 获取到了
Thread-1 获取到了
Thread-2 获取到了
Thread-1
Thread-2
Thread-3 获取到了
Thread-0
Thread-4 获取到了
Thread-3 // 这两个线程获取信号量的时候为0,所以需要等其他线程执行完毕才会执行
Thread-4 //

二,CountDownLatch的使用

      当计数器的值为0时,调用await()方法的线程才会被唤醒,继续往下执行。可用于控制让一个线程在指定线程数的线程执行完毕之后接着执行。

 (1)countDown()方法调用之后,计数器减一,最小为0。

   (2)await()被调用之后,线程阻塞直到计数器的值为0。

  (3)实战

    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        for (int i = 0; i < 4; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {

                    System.out.println(Thread.currentThread().getName());
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    countDownLatch.countDown();

                }
            }).start();
        }
        try {
            countDownLatch.await();
            System.out.println(Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
//运行结果

Thread-0
Thread-1
Thread-2
Thread-3
2
1
0
main //当三个线程执行完毕之后,main才会执行;并且计数器的值最小是为0
0

三,CyclicBarrier的使用

  所有的线程都到达await()方法之后, 统一往下执行。

  (1)await()方法线程阻塞,计数器为0,开始运行。

  (2)reset()方法重置计数器的值

   (3)实战

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
        for (int i = 0; i <3 ; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName()+" 到达状态");
                        cyclicBarrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+
                            " 开始执行");
                }
            }).start();

        }


    }
//运行结果

Thread-0 到达状态
Thread-1 到达状态
Thread-2 到达状态
Thread-0 开始执行
Thread-2 开始执行
Thread-1 开始执行

  (4)CyclicBarrier和CountDownLatch的区别

     CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的;CountDownLatch 参与的线程的职责是不一样的,有的在倒计时,有的在等待倒计时结束。CyclicBarrier 参与的线程职责是一样的。

 
原文地址:https://www.cnblogs.com/amazing-eight/p/13690371.html