共享锁Semaphore、CyclicBarrier、CountDownLatch

Semaphore

Semaphore semaphore = new Semaphore(5);
semaphore.acquire();
semaphore.acquire(n);
semaphore.tryAcquire();
semaphore.release();

依据同步器的共享计数器模式,先设置计数器为5,线程调用acquire方法申请许可数量,申请成功计数器-n个许可数,失败则阻塞等待。
当用完锁后要调用release方法去释放许可数,计数器会+n。

使用场景

做限流,设置最大并发线程数,每个请求过来可用线程数-1,线程执行完毕可用线程数+1。

CyclicBarrier

CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
cyclicBarrier.await();
cyclicBarrier.await(3,TimeUnit.SECONDS);
cyclicBarrier.reset();

依据同步器的共享模式,先设置计数器为5,线程每次调用await方法,都会将计数器-1,再进入线程阻塞状态,当计数器为0的时候,广播唤醒所有阻塞的线程。
如果有一个阻塞的线程被中断,也会唤醒所有阻塞线程。

如果担心条件不满足,程序一直被阻塞下去怎么办?

可以使用带超时的await(time, TimeUnit)方法,会通过LockSupport.parkNanos先暂停一段时间,当到达超时时间,线程醒来后,中断其他阻塞线程,并在当前线程抛出TimeoutException异常。
也可以使用reset()方法,重置条件,中断所有阻塞的线程。

使用场景

需要等待所有条件都满足,大家才能继续往下执行。例如足球比赛,需要每个分组都比完,才能进入下一轮。

CountDownLatch

CountDownLatch countDownLatch = new CountDownLatch(5);
countDownLatch.countDown();
countDownLatch.await();

依据同步器的共享模式,先设置计数器为5,然后每次调用countDown方法来进行计数器-1,等到计数器为0时,就唤醒被阻塞的线程,即调用了await方法的线程。

使用场景

需要等待所有条件都满足,才能往下执行。幼儿园老师要等到小朋友都回家了,他才能回去,而小朋友管自己走就行。

CyclicBarrier与CountDownLatch的区别

CyclicBarrier与CountDownLatch虽然都是计数器,都会产生阻塞,但是阻塞的对象不同。CyclicBarrier是大家要等一起等,CountDownLatch是我等你们先走。另一个区别是CyclicBarrier可以重置计数器。

你可能感兴趣的:(共享锁Semaphore、CyclicBarrier、CountDownLatch)