@@ -238,7 +238,9 @@ tryReleaseShared(int)//共享方式。尝试释放资源,成功则返回true
238
238
239
239
### 3 Semaphore(信号量)-允许多个线程同时访问
240
240
241
- ** synchronized 和 ReentrantLock 都是一次只允许一个线程访问某个资源,Semaphore(信号量)可以指定多个线程同时访问某个资源。** 示例代码如下:
241
+ ** synchronized 和 ReentrantLock 都是一次只允许一个线程访问某个资源,Semaphore(信号量)可以指定多个线程同时访问某个资源。**
242
+
243
+ 示例代码如下:
242
244
243
245
``` java
244
246
/**
@@ -288,9 +290,9 @@ public class SemaphoreExample1 {
288
290
当然一次也可以一次拿取和释放多个许可,不过一般没有必要这样做:
289
291
290
292
``` java
291
- semaphore. acquire(5 );// 获取5个许可,所以可运行线程数量为20/5=4
292
- test(threadnum);
293
- semaphore. release(5 );// 获取5个许可,所以可运行线程数量为20/5=4
293
+ semaphore. acquire(5 );// 获取5个许可,所以可运行线程数量为20/5=4
294
+ test(threadnum);
295
+ semaphore. release(5 );// 获取5个许可,所以可运行线程数量为20/5=4
294
296
```
295
297
296
298
除了 ` acquire ` 方法之外,另一个比较常用的与之对应的方法是` tryAcquire ` 方法,该方法如果获取不到许可就立即返回 false。
@@ -314,21 +316,22 @@ Semaphore 有两种模式,公平模式和非公平模式。
314
316
315
317
** 这两个构造方法,都必须提供许可的数量,第二个构造方法可以指定是公平模式还是非公平模式,默认非公平模式。**
316
318
317
- 由于篇幅问题,如果对 Semaphore 源码感兴趣的朋友可以看下面这篇文章:
319
+ [ issue645补充内容] ( https://github.com/Snailclimb/JavaGuide/issues/645 ) :Semaphore与CountDownLatch一样,也是共享锁的一种实现。它默认构造AQS的state为permits。当执行任务的线程数量超出permits,那么多余的线程将会被放入阻塞队列Park,并自旋判断state是否大于0。只有当state大于0的时候,阻塞的线程才能继续执行,此时先前执行任务的线程继续执行release方法,release方法使得state的变量会加1,那么自旋的线程便会判断成功。
320
+ 如此,每次只有最多不超过permits数量的线程能自旋成功,便限制了执行任务线程的数量。
318
321
319
- - https://blog.csdn.net/qq_19431333/article/details/70212663
322
+ 由于篇幅问题,如果对 Semaphore 源码感兴趣的朋友可以看下这篇文章: https://juejin.im/post/5ae755366fb9a07ab508adc6
320
323
321
324
### 4 CountDownLatch (倒计时器)
322
325
323
- CountDownLatch 是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。在 Java 并发中,countdownlatch 的概念是一个常见的面试题,所以一定要确保你很好的理解了它。
324
-
325
- #### 4.1 CountDownLatch 的三种典型用法
326
+ CountDownLatch允许 count 个线程阻塞在一个地方,直至所有线程的任务都执行完毕。在 Java 并发中,countdownlatch 的概念是一个常见的面试题,所以一定要确保你很好的理解了它。
326
327
327
- ① 某一线程在开始运行前等待 n 个线程执行完毕。将 CountDownLatch 的计数器初始化为 n : ` new CountDownLatch(n) ` ,每当一个任务线程执行完毕,就将计数器减 1 ` countdownlatch.countDown() ` ,当计数器的值变为 0 时,在 ` CountDownLatch上 await() ` 的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行 。
328
+ CountDownLatch是共享锁的一种实现,它默认构造 AQS 的 state 值为 count。当线程使用countDown方法时,其实使用了 ` tryReleaseShared ` 方法以CAS的操作来减少state,直至state为0就代表所有的线程都调用了countDown方法。当调用await方法的时候,如果state不为0,就代表仍然有线程没有调用countDown方法,那么就把已经调用过countDown的线程都放入阻塞队列Park,并自旋CAS判断state == 0,直至最后一个线程调用了countDown,使得state == 0,于是阻塞的线程便判断成功,全部往下执行 。
328
329
329
- ② 实现多个线程开始执行任务的最大并行性。注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的 ` CountDownLatch ` 对象,将其计数器初始化为 1 : ` new CountDownLatch(1) ` ,多个线程在开始执行任务前首先 ` coundownlatch.await() ` ,当主线程调用 countDown() 时,计数器变为 0,多个线程同时被唤醒。
330
+ #### 4.1 CountDownLatch 的三种典型用法
330
331
331
- ③ 死锁检测:一个非常方便的使用场景是,你可以使用 n 个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。
332
+ 1 . 某一线程在开始运行前等待 n 个线程执行完毕。将 CountDownLatch 的计数器初始化为 n :` new CountDownLatch(n) ` ,每当一个任务线程执行完毕,就将计数器减 1 ` countdownlatch.countDown() ` ,当计数器的值变为 0 时,在` CountDownLatch上 await() ` 的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。
333
+ 2 . 实现多个线程开始执行任务的最大并行性。注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的 ` CountDownLatch ` 对象,将其计数器初始化为 1 :` new CountDownLatch(1) ` ,多个线程在开始执行任务前首先 ` coundownlatch.await() ` ,当主线程调用 countDown() 时,计数器变为 0,多个线程同时被唤醒。
334
+ 3 . 死锁检测:一个非常方便的使用场景是,你可以使用 n 个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。
332
335
333
336
#### 4.2 CountDownLatch 的使用示例
334
337
@@ -377,10 +380,12 @@ public class CountDownLatchExample1 {
377
380
378
381
上面的代码中,我们定义了请求的数量为 550,当这 550 个请求被处理完成之后,才会执行` System.out.println("finish"); ` 。
379
382
380
- 与 CountDownLatch 的第一次交互是主线程等待其他线程。主线程必须在启动其他线程后立即调用 CountDownLatch.await()方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。
383
+ 与 CountDownLatch 的第一次交互是主线程等待其他线程。主线程必须在启动其他线程后立即调用 ` CountDownLatch.await() ` 方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。
381
384
382
385
其他 N 个线程必须引用闭锁对象,因为他们需要通知 CountDownLatch 对象,他们已经完成了各自的任务。这种通知机制是通过 CountDownLatch.countDown()方法来完成的;每调用一次这个方法,在构造函数中初始化的 count 值就减 1。所以当 N 个线程都调 用了这个方法,count 的值等于 0,然后主线程就能通过 await()方法,恢复执行自己的任务。
383
386
387
+ 如果对CountDownLatch源码感兴趣的朋友,可以查看: [ 【JUC】JDK1.8源码分析之CountDownLatch(五)] ( https://www.cnblogs.com/leesf456/p/5406191.html )
388
+
384
389
#### 4.3 CountDownLatch 的不足
385
390
386
391
CountDownLatch 是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch 使用完毕后,它不能再次被使用。
@@ -399,6 +404,8 @@ CountDownLatch 类中主要的方法?
399
404
400
405
CyclicBarrier 和 CountDownLatch 非常类似,它也可以实现线程间的技术等待,但是它的功能比 CountDownLatch 更加复杂和强大。主要应用场景和 CountDownLatch 类似。
401
406
407
+ > CountDownLatch的实现是基于AQS的,而CycliBarrier是基于 ReentrantLock(ReentrantLock也属于AQS同步器)和 Condition 的.
408
+
402
409
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier 默认的构造方法是 ` CyclicBarrier(int parties) ` ,其参数表示屏障拦截的线程数量,每个线程调用` await ` 方法告诉 CyclicBarrier 我已经到达了屏障,然后当前线程被阻塞。
403
410
404
411
再来看一下它的构造函数:
0 commit comments