Java高级-JUC二-常用类

CountDownLatch // 计数器

CyclicBarrier // 循环阻塞

Semaphore //信号量

CountDownLatch

java.util.concurrent
Class CountDownLatch

java.lang.Object
java.util.concurrent.CountDownLatch


public class CountDownLatch
extends Object

解释: 允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。

官方解释:

A CountDownLatch用给定的计数初始化。 await方法阻塞,直到由于countDown()方法的调用而导致当前计数达到零,之后所有等待线程被释放,并且任何后续的await 调用立即返回。 这是一个一次性的现象 - 计数无法重置。 如果您需要重置计数的版本,请考虑使用CyclicBarrier

A CountDownLatch是一种通用的同步工具,可用于多种用途。 一个CountDownLatch为一个计数的CountDownLatch用作一个简单的开/关锁存器,或者门:所有线程调用await在门口等待,直到被调用countDown()的线程打开。 一个CountDownLatch初始化N可以用来做一个线程等待,直到N个线程完成某项操作,或某些动作已经完成N次

个人解释:

就是对线程计数,到达指定数量后,继续执行,否则等待

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
*
* @Title: CountDownLatchTest
* @Description: 并发常用类,CountDownLatch 计数器
* @throws InterruptedException 参数
* @return void 返回类型
*/
public static void CountDownLatchTest() throws InterruptedException {
System.out.println("CountDownLatch");
// 计数器
CountDownLatch countDownLatch = new CountDownLatch(10);

for (int i = 0; i < 10; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "撤退!");
// 计数器减一
countDownLatch.countDown();
}, "线程" + i).start();
}
// 当 countDownLatch = 0 , 唤醒线程, 才会继续往下执行
countDownLatch.await();
System.out.println("结果:" + countDownLatch.getCount());

}

结果:

CountDownLatch
线程1撤退!
线程2撤退!
线程5撤退!
线程6撤退!
线程9撤退!
线程0撤退!
线程3撤退!
线程4撤退!
线程7撤退!
线程8撤退!
结果:0 <-countDownLatch 为0 才执行

CyclicBarrier

java.util.concurrent
Class CyclicBarrier

java.lang.Object
java.util.concurrent.CyclicBarrier


public class CyclicBarrier
extends Object

允许一组线程全部等待彼此达到共同屏障点的同步辅助。 循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。 屏障被称为循环 ,因为它可以在等待的线程被释放之后重新使用。

官方解释:

A CyclicBarrier支持一个可选的Runnable命令,每个屏障点运行一次,在派对中的最后一个线程到达之后,但在任何线程释放之前。 在任何一方继续进行之前,此屏障操作对更新共享状态很有用。

个人解释:

当阻塞的线程到达一定的数量,线程才会继续执行cyclicBarrier定义好的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void CyclicBarrierTest() {
System.out.println("CyclicBarrier");
CyclicBarrier cyclicBarrier = new CyclicBarrier(9, () -> {
System.out.println("九之极, 万物演化");
});

for (int i = 0; i < 9; i++) {
int a = i;
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "取得数据: " + a);
try {
// 当给定数量的线程等待它时,它才会继续执行
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}, "线程" + i).start();
}

// 获取等待线程的数量
System.out.println("获取等待线程的数量 " + cyclicBarrier.getParties());
}

CyclicBarrier
线程0取得数据: 0
线程3取得数据: 3
线程4取得数据: 4
线程1取得数据: 1
线程2取得数据: 2
获取等待线程的数量 9
线程6取得数据: 6
线程5取得数据: 5
线程7取得数据: 7
线程8取得数据: 8
九之极, 万物演化 <- 9

Semaphore

java.util.concurrent
Class Semaphore
java.lang.Object
java.util.concurrent.Semaphore

All Implemented Interfaces:
Serializable


public class Semaphore
extends Object
implements Serializable

一个计数信号量。 在概念上,信号量维持一组许可证。 如果有必要,每个acquire()都会阻塞,直到许可证可用,然后才能使用它。 每个release()添加许可证,潜在地释放阻塞获取方。 但是,没有使用实际的许可证对象; Semaphore只保留可用数量的计数,并相应地执行。

官方解释:

​ 信号量通常用于限制线程数,而不是访问某些(物理或逻辑)资源。 例如,这是一个使用信号量来控制对一个项目池的访问的类

​ 在获得项目之前,每个线程必须从信号量获取许可证,以确保某个项目可用。 当线程完成该项目后,它将返回到池中,并将许可证返回到信号量,允许另一个线程获取该项目。 请注意,当调用acquire()时,不会保持同步锁定,因为这将阻止某个项目返回到池中。 信号量封装了限制对池的访问所需的同步,与保持池本身一致性所需的任何同步分开。

个人解释:

相当于 限流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static void SemaphoreTest() {
// 定义信号量 维持2个许可证
Semaphore semaphore = new Semaphore(2);
for (int i = 0; i < 9; i++) {
int a = i;
new Thread(() -> {
try {
// 从该信号量获取许可证,阻止直到可用,或线程为 interrupted (中断)。
semaphore.acquire();

System.out.println(Thread.currentThread().getName() + "取得数据: " + a);
TimeUnit.SECONDS.sleep(1);
System.out.println("等待线程数: " + semaphore.getQueueLength());
System.out.println(Thread.currentThread().getName() + ":1秒后丢弃数据: " + a);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放许可证,将其返回到信号量
semaphore.release();
}
}, "线程" + i).start();
}
}

结果:

线程2取得数据: 2
线程0取得数据: 0
等待线程数: 7 <–
等待线程数: 7 <–
线程2:1秒后丢弃数据: 2
线程0:1秒后丢弃数据: 0
线程1取得数据: 1
线程3取得数据: 3
等待线程数: 5 <–
等待线程数: 5 <–
线程1:1秒后丢弃数据: 1
线程3:1秒后丢弃数据: 3
线程5取得数据: 5
线程6取得数据: 6
等待线程数: 3 <–
线程5:1秒后丢弃数据: 5
等待线程数: 3 <–
线程4取得数据: 4
线程6:1秒后丢弃数据: 6
线程7取得数据: 7
等待线程数: 1 <–
线程4:1秒后丢弃数据: 4
等待线程数: 1 <–
线程7:1秒后丢弃数据: 7
线程8取得数据: 8
等待线程数: 0 <–
线程8:1秒后丢弃数据: 8

小唠嗑:

本章到这里就结束了,谢谢耐心看到这里的各位Boss,如果觉得有哪里说的不好的地方,还请高抬贵手多多原谅,不惜指教。

最后,谢谢!

---本文结束感谢您的阅读!---