Java——JAVA并发工具类(一文搞懂Java的并发编程工具类CycliBarriar、CountdownLatch和Semaphore)

1、在JavaCycliBarriarCountdownLatch 有什么区别?

答: CountDownLatchCyclicBarrier都是用于控制并发的工具类,都可以理解成维护的就是一个计数器,但是这两者还是各有不同侧重点的:

  • CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;
  • CountDownLatch强调一个线程等多个线程完成某件事情CyclicBarrier是多个线程互等,等大家都完成,再携手共进。
  • 调用CountDownLatchcountDown方法后,当前线程并不会阻塞,会继续往下执行;而调用CyclicBarrierawait方法,会阻塞当前线程,直到CyclicBarrier指定的线程全部都到达了指定点的时候,才能继续往下执行;
  • CountDownLatch方法比较少,操作比较简单,而CyclicBarrier提供的方法更多,比如能够通过getNumberWaiting()isBroken()这些方法获取当前多个线程的状态,并且CyclicBarrier的构造方法可以传入barrierAction,指定当所有线程都到达时执行的业务功能;
  • CountDownLatch是不能复用的,而CyclicLatch是可以复用的。

1.1、CyclicBarrier 的用法

CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程使用await()方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。

public class CyclicBarrierTest {
  // 自定义工作线程
  private static class Worker extends Thread {
    private CyclicBarrier cyclicBarrier;
    
    public Worker(CyclicBarrier cyclicBarrier) {
      this.cyclicBarrier = cyclicBarrier;
    }
    
    @Override
    public void run() {
      super.run();
      
      try {
        System.out.println(Thread.currentThread().getName() + "开始等待其他线程");
        cyclicBarrier.await();
        System.out.println(Thread.currentThread().getName() + "开始执行");
        // 工作线程开始处理,这里用Thread.sleep()来模拟业务处理
        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName() + "执行完毕");
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
 
  public static void main(String[] args) {
    int threadCount = 3;
    CyclicBarrier cyclicBarrier = new CyclicBarrier(threadCount);
    
    for (int i = 0; i < threadCount; i++) {
      System.out.println("创建工作线程" + i);
      Worker worker = new Worker(cyclicBarrier);
      worker.start();
    }
  }
}

1.2、CountdownLatch 的用法

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 主线程等待子线程执行完成再执行
 */
public class CountdownLatchTest1 {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(3);
        final CountDownLatch latch = new CountDownLatch(3);
        for (int i = 0; i < 3; i++) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("子线程" + Thread.currentThread().getName() + "开始执行");
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("子线程"+Thread.currentThread().getName()+"执行完成");
                        latch.countDown();//当前线程调用此方法,则计数减一
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            service.execute(runnable);
        }

        try {
            System.out.println("主线程"+Thread.currentThread().getName()+"等待子线程执行完成...");
            latch.await();//阻塞当前线程,直到计数器的值为0
            System.out.println("主线程"+Thread.currentThread().getName()+"开始执行...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

2、Semaphore 有什么作用?

答:Semaphore 就是一个信号量,它的作用是限制某段代码块的并发数Semaphore有一个构造函数,可以传入一个int 型整数 n,表示某段代码最多只有 n个线程可以访问,如果超出了n,那么请等待,等到某个线程执行完毕这段代码块,下一个线程再进入。由此可以看出如果 Semaphore 构造函数中传入的 int 型整数 n=1,相当于变成了一个 synchronized 了。

Semaphore (信号量)-允许多个线程同时访问: synchronizedReentrantLock 都是一次只允许一个线程访问某个资源,Semaphore(信号量)可以指定多个线程同时访问某个资源。

import java.util.Random;
import java.util.concurrent.Semaphore;

public class TestCar {
    // 停车场同时容纳的车辆10

    private static Semaphore semaphore = new Semaphore(10);

    public static void main(String[] args) {
        //模拟100辆车进入停车场
        for (int i = 0; i < 100; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("====" + Thread.currentThread().getName() + "来到停车场");
                        if (semaphore.availablePermits() == 0) {
                            System.out.println("车位不足,请耐心等待");
                        }
                        semaphore.acquire();//获取令牌尝试进入停车场
                        System.out.println(Thread.currentThread().getName() + "成功进入停车场");
                        Thread.sleep(new Random().nextInt(10000));//模拟车辆在停车场停留的时间
                        System.out.println(Thread.currentThread().getName() + "驶出停车场");
                        semaphore.release();//释放令牌,腾出停车场车位
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, i + "号车");

            thread.start();
        }
    }
}

3、常用的并发工具类有哪些?

  • Semaphore (信号量)-允许多个线程同时访问: synchronizedReentrantLock 都是一次只允许一个线程访问某个资源Semaphore(信号量)可以指定多个线程同时访问某个资源
  • CountDownLatch (倒计时器):CountDownLatch是一个同步工具类,用来协调多个线程之间的同步。这个工具通常用来控制线程等待,它可以让某一个线程等待直到倒计时结束,再开始执行。
  • CyclicBarrier (循环栅栏):CyclicBarrierCountDownLatch 非常类似,它也可以实现线程间的技术等待,但是它的功能比 CountDownLatch 更加复杂和强大。主要应用场景和CountDownLatch 类似。CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await()方法告诉CyclicBarrier 我已经到达了屏障,然后当前线程被阻塞。

你可能感兴趣的:(Java,java,算法)