GitHub:https://github.com/yihonglei/thinking-in-concurrent
T1、T2、T3如何保证线程顺序执行?
直接上Demo吧!
Join方法是最常用的方式,底层通过wait即加了synchronized同步锁和notify通知逻辑实现。
Join实现原理:https://blog.csdn.net/u010983881/article/details/80257703
package com.jpeony.concurrent.threadorder;
/**
* join控制线程顺序执行
*
* @author yihonglei
*/
public class ThreadJoinOrder {
public static void main(String[] args) throws InterruptedException {
// 创建线程
Thread t1 = new Thread(new Work(), "Thread-1");
Thread t2 = new Thread(new Work(), "Thread-2");
Thread t3 = new Thread(new Work(), "Thread-3");
// 调用join
t1.join();
t2.join();
t3.join();
// 启动线程
t1.start();
t2.start();
t3.start();
}
static class Work implements Runnable {
@Override
public void run() {
System.out.println("thread start:" + Thread.currentThread().getName());
}
}
}
运行结果:
通过FutureTask的get()方法阻塞特性,控制线程顺序。
package com.jpeony.concurrent.threadorder;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
* FutureTask控制线程顺序,通过get方法阻塞获取上一个线程结果,只有当上一个线程执行完成并返回结果时,才继续执行下一个线程。
*
* @author yihonglei
*/
public class FutureTaskOrder {
public static void main(String[] args) {
// 创建FutureTask
FutureTask task1 = new FutureTask<>(new Work(null));
FutureTask task2 = new FutureTask<>(new Work(task1));
FutureTask task3 = new FutureTask<>(new Work(task2));
// 创建线程
Thread t1 = new Thread(task1, "Thread-1");
Thread t2 = new Thread(task2, "Thread-2");
Thread t3 = new Thread(task3, "Thread-3");
// 启动线程
t1.start();
t2.start();
t3.start();
}
static class Work implements Callable {
private FutureTask beforeTask;
Work(FutureTask beforeTask) {
this.beforeTask = beforeTask;
}
@Override
public String call() throws Exception {
if (beforeTask != null) {
// 阻塞等待,上一个线程执行完,才能继续执行
beforeTask.get();
System.out.println("thread start:" + Thread.currentThread().getName());
} else {
System.out.println("thread start:" + Thread.currentThread().getName());
}
return "Result " + Thread.currentThread().getName();
}
}
}
运行结果:
Executors.newSingleThreadExecutor():线程池只有一个工作线程,工作线程从BlockingQueue阻塞有序队列取任务执行,
从而保证线程的顺序性执行。
线程池实现原理:https://blog.csdn.net/yhl_jxy/article/details/86677049
package com.jpeony.concurrent.threadorder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Executors.newSingleThreadExecutor():线程池只有一个工作线程,工作线程从BlockingQueue阻塞有序队列取任务执行,
* 从而保证线程的顺序性执行。
*
* @author yihonglei
*/
public class NewSingleThreadExecutorOrder {
public static void main(String[] args) {
// 单个线程池,保证线程依次执行顺序
ExecutorService executorService = Executors.newSingleThreadExecutor();
// 创建线程
Thread t1 = new Thread(new Work("one"));
Thread t2 = new Thread(new Work("two"));
Thread t3 = new Thread(new Work("three"));
// 提交线程池
executorService.submit(t1);
executorService.submit(t2);
executorService.submit(t3);
// 关闭线程池
executorService.shutdown();
}
static class Work implements Runnable {
private String orderName;
Work(String orderName) {
this.orderName = orderName;
}
@Override
public void run() {
System.out.println("thread start:" + orderName);
}
}
}
运行结果:
CompletableFuture为Java8新特性。
CompletableFuture使用说明:https://juejin.im/post/5edf454c518825433a57c4c9
package com.jpeony.concurrent.threadorder;
import java.util.concurrent.CompletableFuture;
/**
* CompletableFuture顺序执行任务
*
* @author yihonglei
*/
public class CompletableFutureOrder {
public static void main(String[] args) {
CompletableFuture cf = CompletableFuture.supplyAsync(() -> {
System.out.println("Thread-1");
return "one";
});
cf.thenRun(() -> {
System.out.println("Thread-2");
});
cf.thenRun(() -> {
System.out.println("Thread-3");
});
}
}
运行结果:
通过阻塞队列+while循环控制线程的顺序性,或者通过ArrayList控制线程的顺序,
但是需要在每个线程执行完成时自己从队列移出元素。
package com.jpeony.concurrent.threadorder;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* 通过阻塞队列+while循环控制线程的顺序性,或者通过ArrayList控制线程的顺序,但是需要在每个线程执行完成时自己从队列移出元素。
*
* @author yihonglei
*/
public class BlockingQueueOrder {
public static void main(String[] args) throws InterruptedException {
// 创建线程
Thread t1 = new Thread(new Work(), "Thread-1");
Thread t2 = new Thread(new Work(), "Thread-2");
Thread t3 = new Thread(new Work(), "Thread-3");
// 队列保证顺序性
BlockingQueue blockingQueue = new LinkedBlockingQueue<>();
blockingQueue.add(t1);
blockingQueue.add(t2);
blockingQueue.add(t3);
for (int i = 0; i < 3; i++) {
Thread take = blockingQueue.take();
take.start();
while (take.isAlive()) ;
}
// 主线程保持存活
Thread.sleep(3000);
}
static class Work implements Runnable {
@Override
public void run() {
System.out.println("thread start:" + Thread.currentThread().getName());
}
}
}
运行结果:
CountDownLatch控制线程执行顺序,通过await方法为0时,线程才会执行特性,阻塞线程执行,通过上一个线程执行完成,
减掉下一个线程的计数器,使下一个线程计数器为0,线程变为可执行,来控制线程执行顺序。
CountDownLatch实现原理:https://blog.csdn.net/yhl_jxy/article/details/87181895
package com.jpeony.concurrent.threadorder;
import java.util.concurrent.CountDownLatch;
/**
* CountDownLatch控制线程执行顺序,通过await方法为0时,线程才会执行特性,阻塞线程执行,通过上一个线程执行完成,
* 减掉下一个线程的计数器,使下一个线程计数器为0,线程变为可执行,来控制线程执行顺序。
*
* @author yihonglei
*/
public class CountDownLatchOrder {
public static void main(String[] args) {
// 计数器为0
CountDownLatch threadC1 = new CountDownLatch(0);
// 计数器为1
CountDownLatch threadC2 = new CountDownLatch(1);
// 计算器为2
CountDownLatch threadC3 = new CountDownLatch(1);
// threadC1计数器为0,t1线程执行,然后threadC2计数器被减为0
Thread t1 = new Thread(new Work(threadC1, threadC2), "Thread-1");
// threadC2计数器为0,t2线程执行,然后threadC3计数器被减为0
Thread t2 = new Thread(new Work(threadC2, threadC3), "Thread-2");
// threadC3计数器为0,t3线程执行
Thread t3 = new Thread(new Work(threadC3, threadC3), "Thread-3");
// 启动线程
t1.start();
t2.start();
t3.start();
}
static class Work implements Runnable {
// 当前要执行线程的计数器
private CountDownLatch current;
// 下一个要执行线程的计数器
private CountDownLatch next;
Work(CountDownLatch current, CountDownLatch next) {
this.current = current;
this.next = next;
}
@Override
public void run() {
try {
// 计数器为0,则可执行,否则线程被阻塞
current.await();
System.out.println("thread start:" + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 计数器减1,将计数器变为0,通知等待线程尝试获取锁执行
next.countDown();
}
}
}
}
运行结果: