2021年9月12日面试茄子快传的时候,提到三个任务T1
、T2
、T3
的执行需要并发执行,且最后执行任务T4
。那么应该怎么实现。
当时有点忘记了具体的实现,只知道在Java
中,如果抽象为线程任务,那么有两种机制可以用来实现:
Thread
提供的join
方法;- 使用
JUC
下面的CountDownLatch
类;
这里来简单使用下这两种方法。
1. join方法来实现
等待线程执行终止。
在主线程中如果对子线程使用了join
方法,那么主线程会等待join
的线程执行完毕,当所有的执行完毕后,再继续向下执行主线程。
故而在当前的场景下,可以构建如下代码:
public class Main {
private static volatile int[] arr = new int[4];
private static class ThreadFactory{
private static AtomicInteger number = new AtomicInteger(1);
private ThreadFactory(){
}
public static Thread createThread(Runnable r){
return new Thread(r, "Task#" + number.getAndIncrement());
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = ThreadFactory.createThread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
arr[0] += 10;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t" + arr[0]);
}
}
});
thread1.start();
Thread thread2 = ThreadFactory.createThread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
arr[1] += 20;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t" + arr[1]);
}
}
});
thread2.start();
Thread thread3 = ThreadFactory.createThread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
arr[2] += 30;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t" + arr[2]);
}
}
});
thread3.start();
thread1.join();
thread2.join();
thread3.join();
// Task 4默认为主线程即可
arr[3] = arr[0] + arr[1] + arr[2];
for (int i : arr) {
System.out.print(i+"\t");
}
System.out.println();
}
}
结果:
从上面结果可以看出满足了T1
、T2
、T3
并发执行,最后执行任务T4
的要求。
2. CountDownLatch类来实现
CountDownLatch
是一个同步工具类,用来协调多个线程之间的同步。当计数器数值减为0
时,所有受其影响而等待的线程将会被激活。
CountDownLatch
主要两个方法就是一是CountDownLatch.await()
阻塞当前线程,二是CountDownLatch.countDown()
当前线程把计数器减一。
对应的实现:
public class Main {
private static volatile int[] arr = new int[4];
private static class ThreadFactory{
private static AtomicInteger number = new AtomicInteger(1);
private ThreadFactory(){
}
public static Thread createThread(Runnable r){
return new Thread(r, "Task#" + number.getAndIncrement());
}
}
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(3); // 这里需要三个并发,故而这里设置值为3
Thread thread1 = ThreadFactory.createThread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
arr[0] += 10;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t" + arr[0]);
}
// 这个线程执行完毕,进行释放
countDownLatch.countDown();
}
});
thread1.start();
Thread thread2 = ThreadFactory.createThread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
arr[1] += 20;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t" + arr[1]);
}
// 这个线程执行完毕,进行释放
countDownLatch.countDown();
}
});
thread2.start();
Thread thread3 = ThreadFactory.createThread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
arr[2] += 30;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t" + arr[2]);
}
// 这个线程执行完毕,进行释放
countDownLatch.countDown();
}
});
thread3.start();
// Task 4默认为主线程即可
// 首先阻塞一下
countDownLatch.await();
arr[3] = arr[0] + arr[1] + arr[2];
for (int i : arr) {
System.out.print(i+"\t");
}
System.out.println();
}
}
结果: