Java Semaphore、CyclicBarrier、CountDownLatch

问:如何控制某个方法被并发访问的个数?

答:可以使用 Semaphore,其有两个核心方法如下:

  • semaphore.acquire():用来请求一个信号量,该方法使信号量个数减 1;一旦没有可使用的信号量,即信号量个数变为负数时,再次调用该方法请求时就会阻塞,直到其他线程释放了信号量。

  • semaphore.release():用来释放一个信号量,该方法使信号量个数加 1。

所以本题最简单的实现方案代码如下(同时最多可以 5 个并发访问):

public class SemaphoreTest {  
    private Semaphore mSemaphore = new Semaphore(5);  

    public void testRun() {  
        for(int i=0; i< 20; i++){  
            new Thread(new Runnable() {  
                @Override  
                public void run() {  
                    test();  
                }  
            }).start();  
        }  
    }  

    private void test(){  
        try {  
            mSemaphore.acquire();  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println(Thread.currentThread().getName() + " enter...");  
        try {  
            Thread.sleep(100);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println(Thread.currentThread().getName() + " exit...");  
        mSemaphore.release();  
    }  
} 

输出如下:

Thread-1 enter...
Thread-2 enter...
Thread-3 enter...
Thread-4 enter...
Thread-5 enter...
Thread-1 exit...
Thread-6 enter...
Thread-2 exit...
Thread-7 enter...
Thread-3 exit...
Thread-8 enter...
Thread-4 exit...
Thread-9 enter...
Thread-5 exit...
Thread-10 enter...
Thread-7 exit...
Thread-6 exit...
Thread-11 enter...
Thread-12 enter...
Thread-8 exit...
Thread-13 enter...
Thread-10 exit...
Thread-14 enter...
Thread-9 exit...
Thread-15 enter...
Thread-11 exit...
Thread-12 exit...
Thread-16 enter...
Thread-17 enter...
Thread-15 exit...
Thread-18 enter...
Thread-14 exit...
Thread-19 enter...
Thread-13 exit...
Thread-20 enter...
Thread-16 exit...
Thread-19 exit...
Thread-17 exit...
Thread-18 exit...
Thread-20 exit...
问:简单说说 Java 中 CyclicBarrier 和 CountDownLatch 有什么不同?

答:CountDownLatch 和 CyclicBarrier 都能够实现线程之间的等待,只不过它们侧重点不同。

  • CountDownLatch 一般用于某个线程 A 等待若干个其他线程执行完任务之后,它才执行。

  • CyclicBarrier 一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行。

  • 此外,CountDownLatch 是不能够重用的,而 CyclicBarrier 是可以重用的。

如下是 CountDownLatch 使用样例:

public class Test {
     public static void main(String[] args) {   
         final CountDownLatch latch = new CountDownLatch(2);

         new Thread(){
             public void run() {
                 try {
                     System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
                    Thread.sleep(3000);
                    System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
             };
         }.start();

         new Thread(){
             public void run() {
                 try {
                     System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
                     Thread.sleep(3000);
                     System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
                     latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
             };
         }.start();

         try {
             System.out.println("等待2个子线程执行完毕...");
            latch.await();
            System.out.println("2个子线程已经执行完毕");
            System.out.println("继续执行主线程");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
     }
}

如下是 CyclicBarrier 使用样例:

public class Test {
    public static void main(String[] args) {
        int N = 4;

        CyclicBarrier barrier  = new CyclicBarrier(N,new Runnable() {
            @Override
            public void run() {
                System.out.println("当前线程"+Thread.currentThread().getName());   
            }
        });

        for(int i=0;i

本文参考自 Semaphore、CyclicBarrier、CountDownLatch 神器相关的面试题解析

你可能感兴趣的:(Java Semaphore、CyclicBarrier、CountDownLatch)