之前学多线程的时候没有学习线程的同步工具类(辅助类)。ps:当时觉得暂时用不上,认为是挺高深的知识点就没去管了..
在前几天,朋友发了一篇比较好的Semaphore文章过来,然后在浏览博客的时候又发现面试还会考,那还是挺重要的知识点。于是花了点时间去了解一下。
Java为我们提供了三个同步工具类:
这几个工具类其实说白了就是为了能够更好控制线程之间的通讯问题~
- A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
简单来说:CountDownLatch是一个同步的辅助类,允许一个或多个线程一直等待,直到其它线程完成它们的操作。
它常用的API其实就两个:await()
和countDown()
使用说明:
countDown()
使计数器count减1。当count减到0时,所有在等待的线程均会被释放例子:3y现在去做实习生了,其他的员工还没下班,3y不好意思先走,等其他的员工都走光了,3y再走。
import java.util.concurrent.CountDownLatch;
public class Test {
public static void main(String[] args) {
final CountDownLatch countDownLatch = new CountDownLatch(5);
System.out.println("现在6点下班了.....");
// 3y线程启动
new Thread(new Runnable() {
@Override
public void run() {
try {
// 这里调用的是await()不是wait()
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("...其他的5个员工走光了,3y终于可以走了");
}
}).start();
// 其他员工线程启动
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("员工xxxx下班了");
countDownLatch.countDown();
}
}).start();
}
}
}
输出结果:
再写个例子:3y现在负责仓库模块功能,但是能力太差了,写得很慢,别的员工都需要等3y写好了才能继续往下写。
import java.util.concurrent.CountDownLatch;
public class Test {
public static void main(String[] args) {
final CountDownLatch countDownLatch = new CountDownLatch(1);
// 3y线程启动
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("3y终于写完了");
countDownLatch.countDown();
}
}).start();
// 其他员工线程启动
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("其他员工需要等待3y");
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("3y终于写完了,其他员工可以开始了!");
}
}).start();
}
}
}
输出结果:
参考资料:
- A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other. The barrier is called cyclic because it can be re-used after the waiting threads are released.
简单来说:CyclicBarrier允许一组线程互相等待,直到到达某个公共屏障点。叫做cyclic是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用(对比于CountDownLatch是不能重用的)
使用说明:
例子:3y和女朋友约了去广州夜上海吃东西,由于3y和3y女朋友住的地方不同,自然去的路径也就不一样了。于是他俩约定在体育西路地铁站集合,约定等到相互见面的时候就发一条朋友圈。
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class Test {
public static void main(String[] args) {
final CyclicBarrier CyclicBarrier = new CyclicBarrier(2);
for (int i = 0; i < 2; i++) {
new Thread(() -> {
String name = Thread.currentThread().getName();
if (name.equals("Thread-0")) {
name = "3y";
} else {
name = "女朋友";
}
System.out.println(name + "到了体育西");
try {
// 两个人都要到体育西才能发朋友圈
CyclicBarrier.await();
// 他俩到达了体育西,看见了对方发了一条朋友圈:
System.out.println("跟" + name + "去夜上海吃东西~");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
测试结果:
玩了一天以后,各自回到家里,3y和女朋友约定各自洗澡完之后再聊天
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class Test {
public static void main(String[] args) {
final CyclicBarrier CyclicBarrier = new CyclicBarrier(2);
for (int i = 0; i < 2; i++) {
new Thread(() -> {
String name = Thread.currentThread().getName();
if (name.equals("Thread-0")) {
name = "3y";
} else {
name = "女朋友";
}
System.out.println(name + "到了体育西");
try {
// 两个人都要到体育西才能发朋友圈
CyclicBarrier.await();
// 他俩到达了体育西,看见了对方发了一条朋友圈:
System.out.println("跟" + name + "去夜上海吃东西~");
// 回家
CyclicBarrier.await();
System.out.println(name + "洗澡");
// 洗澡完之后一起聊天
CyclicBarrier.await();
System.out.println("一起聊天");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
测试结果:
参考资料:
>>>>阅读全文