一 初始化线程的四种方式
- 继承Thread
- 实现Runnable
- 实现Runnable接口+FutureTask
- 线程池
二 线程池是什么?
线程池类似数据库连接池,在线程池中,总有那么几个活跃的线程。当你需要使用线程时,可以从池子中随便拿一个空闲的线程使用,待完成工作,将线程归还给线程池。
三 线程池的分类
1.Executors
Executors类扮演着线程工厂的角色,使用该类的静态方法可以获取特点功能的线程池。
1.1 newFixedThreadPool()
该方法返回固定线程数量的线程池。LinkedBlockingQueue
public static class MyTask implements Runnable{
@Override
public void run() {
//获取当前时间的毫秒数+:Thread Id:+当前线程的Id作为标识
String threadName = System.currentTimeMillis()+
":Thread Id:"+Thread.currentThread().getId();
System.out.println(threadName+"start");
try {
//sleep()不会释放锁,wait会释放锁
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName+"end");
}
}
public static void main(String[] args) {
MyTask task = new MyTask();
ExecutorService executorService = Executors.newFixedThreadPool(5);
System.out.println("main:"+Thread.currentThread().getId()+"start");
for(int i=0;i<10;i++){
executorService.submit(task);
}
System.out.println("main:"+Thread.currentThread().getId()+"end");
}
main:1start
1604731505456:Thread Id:11start
1604731505456:Thread Id:12start
1604731505456:Thread Id:12end
1604731506473:Thread Id:12start
1604731505456:Thread Id:11end
1604731506473:Thread Id:12end
main:1end
1.2 newSingleThreadExecutor()
该方法返回一个只有一个线程的线程池。LinkedBlockingQueue
1.3 newCachedThreadPool()
该方法返回一个可根据实际情况调整线程数量的线程池。当开启10个线程时,通过id可知,线程池中加有10个线程,该方法会根据cpu的资源占用自动调整线程池的大小。SynchronousQueue
public static void main(String[] args) {
MyTask task = new MyTask();
ExecutorService executorService = Executors.newCachedThreadPool();
System.out.println("main:"+Thread.currentThread().getId()+"start");
for(int i=0;i<10;i++){
executorService.submit(task);
}
try {
Thread.sleep(5000);
System.out.println("main:"+Thread.currentThread().getId()+"end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
1.4 newSingleThreadScheduledExecutor()
该方法返回一个ScheduledExecutorService对象,线程池大小为1。可以实现线程周期性执行和延迟执行。
1.5 newScheduledThreadPool()
该方法返回一个ScheduledExecutorService对象,可指定线程池的线程数量。
/**
command:任务
delay:延迟时间
TimeUnit:单位 给定单元粒度的时间段
**/
schedule(Runnable command,long delay, TimeUnit unit);
/**
command:任务
initialDelay:初始延迟时间
period:周期的时间
unit:单位
第一次:initialDelay+0*period
第二次:initialDelay+1*period
...
**/
scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)
/**
command:任务
initialDelay:初始延迟时间
delay:延迟时间
第一次:initialDelay
第二次:第一次的结束时间+delay
**/
scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)
注意:任务遇到异常,后续的所有子任务都会停止调度。
四 ThreadPoolExecutor
以上介绍的线程池都是基于ThreadPoolExecutor类的封装
ThreadPoolExecutor(int corePoolSize,//指定线程池中的线程数量
int maximumPoolSize,//指定线程池中的最大线程数
long keepAliveTime,
/**
当线程池中的线程数超过corePoolSize,
多余空闲线程的存活时间
**/
TimeUnit unit,//时间单位
BlockingQueue<Runnable> workQueue,//任务队列
ThreadFactory threadFactory,//线程工厂
RejectedExecutionHandler handler)//决绝策略
3.1BlockingQueue
workQueue:提交但未执行的任务队列。
- SynchronousQueue:直接提交的队列(不会真实的存储任务,都会交给线程执行,没有空闲线程时执行拒绝策略)
- ArrayBlockingQueue:有界的任务队列。当新任务执行,若实际线程数少于corePoolSize,优先创建新线程,若大于corePoolSize,将任务加入等待队列。若队列已满,无法加入,若总线程<maximumPoolSize,创建新的线程,否则,执行拒绝策略。
- LinkedBlockingQueue:无界的任务队列。
- PriorityBlockingkQueue:优先任务队列。可以控制任务的执行先后顺序,类似无界任务队列,可以根据任务自身的优先级先后执行。
3.2 RejectedExecutionHandler
handler:拒绝策略,当任务数量超过了系统的负载,就会使用到拒绝策略。
- AbortPolicy策略:直接抛出异常,阻止系统正常工作。
- CallerRunsPolicty策略:只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务。
- DiscardOldPolicty策略:该策略会丢弃即将执行的任务,并尝试再次提交任务。
- DiscardPolcty策略:默默丢弃无法处理的任务。
ThreadFactory:线程工厂是一个接口。只定义了一个用来创建线程的方法。
public interface ThreadFactory {
Thread newThread(Runnable r);
}
五 扩展线程池
ThreadPoolExecutor 是一个可以扩展的线程池。它提供了beforeExecutor()、afterExecutor()/terminated()三个接口用来对线程池进行控制。
public class MyThreadPool {
public static class MyTask implements Runnable{
private String name;
public MyTask(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("正在执行"+":Thread Id"+Thread.currentThread().getId()
+",Task Name"+name);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService es = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>()){
@Override
protected void beforeExecute(Thread t, Runnable r) {
System.out.println("准备执行:"+((MyTask) r).name);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
System.out.println("执行完成:"+((MyTask) r).name);
}
@Override
protected void terminated() {
System.out.println("线程池退出");
}
};
for(int i=0;i<5;i++){
MyTask myTask = new MyTask("Task"+i);
es.execute(myTask);
Thread.sleep(10);
}
es.shutdown();
}
}
线程池的优势
- 降低资源的消耗
- 通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
- 提高响应速度
- 因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行
- 提高线程的可管理性
- 线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池进行统一分配
六 CompletableFuture 异步编排
以下example都采用如下线程池
public static ExecutorService executor = Executors.newFixedThreadPool(10);
1 runAsync 异步执行,不带返回结果
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable,Executor executor)
public static void main(String[] args) {
log.info("main 线程开始-----------------------");
CompletableFuture<Void> future = CompletableFuture.runAsync(()->{
log.info("当前线程:"+Thread.currentThread().getName()+"开始-----------------------");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("当前线程:"+Thread.currentThread().getName()+"结束-----------------------");
},executor);
log.info("main 线程结束-----------------------");
}
2 supplyAsync 异步执行,带返回结果
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor)
public static void main(String[] args) throws ExecutionException, InterruptedException {
log.info("main 线程开始-----------------------");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
int result = 100 / 2;
log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
return result;
}, executor);
log.info("main 线程结束----------------------- result="+future.get());
}
3 whenComplete 成功回调
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor)
public static void main(String[] args) throws ExecutionException, InterruptedException {
log.info("main 线程开始-----------------------");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
//int result = 100 / 2;
int result = 1/0;
log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
return result;
}, executor).whenComplete((res,exception)->{
log.info("调用成功,返回结果是:"+res+" 异常是:"+exception);
});
log.info("main 线程结束-----------------------");
}
4 exceptionally 异常回调
CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)
public static void main(String[] args) throws ExecutionException, InterruptedException {
log.info("main 线程开始-----------------------");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
//int result = 100 / 2;
int result = 1/0;
log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
return result;
}, executor).whenComplete((res,exception)->{
log.info("调用成功,返回结果是:"+res+" 异常是:"+exception);
}).exceptionally(throwable -> 10);
log.info("main 线程结束-----------------------"+future.get());
}
5 handle 方法执行完后处理
public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn)
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor)
public static void main(String[] args) throws ExecutionException, InterruptedException {
log.info("main 线程开始-----------------------");
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
int result = 100 / 2;
//int result = 1/0;
log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
return result;
}, executor).handle((res,exception)->{
//res 结果 exception 异常
if(res!=null){
return res;
}
if(exception!=null){
return 0;
}
return 0;
});
log.info("main 线程结束-----------------------"+future.get());
}
6 线程串行化方法
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
public CompletableFuture<Void> thenAccept(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,Executor executor)
public CompletableFuture<Void> thenRun(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action)
public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor)
thenRun 同样线程执行B任务,无返回值,不能接收上一步返回的结果
log.info("main 线程开始-----------------------");
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
int result = 100 / 2;
log.info("A任务开始执行");
//int result = 1/0;
log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
return result;
}, executor).thenRun(()->{
log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
int result = 100 / 2;
log.info("B任务开始执行");
//int result = 1/0;
log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
});
log.info("main 线程结束-----------------------"+future.get());
thenRunAsync 开启新线程执行B任务,无返回值,不能接收上一步返回的结果
log.info("main 线程开始-----------------------");
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
int result = 100 / 2;
log.info("A任务开始执行");
//int result = 1/0;
log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
return result;
}, executor).thenRunAsync(()->{
log.info("当前线程:" + Thread.currentThread().getName() + "开始-----------------------");
int result = 100 / 2;
log.info("B任务开始执行");
//int result = 1/0;
log.info("当前线程:" + Thread.currentThread().getName() + "结束-----------------------");
},executor);
log.info("main 线程结束-----------------------"+future.get());
7 两任务组合 - 都要完成
public <U,V> CompletableFuture<V> thenCombine(
CompletionStage<? extends U> other,
BiFunction<? super T,? super U,? extends V> fn) {
return biApplyStage(null, other, fn);
}
public <U,V> CompletableFuture<V> thenCombineAsync(
CompletionStage<? extends U> other,
BiFunction<? super T,? super U,? extends V> fn) {
return biApplyStage(asyncPool, other, fn);
}
public <U,V> CompletableFuture<V> thenCombineAsync(
CompletionStage<? extends U> other,
BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
return biApplyStage(screenExecutor(executor), other, fn);
}
public <U> CompletableFuture<Void> thenAcceptBoth(
CompletionStage<? extends U> other,
BiConsumer<? super T, ? super U> action) {
return biAcceptStage(null, other, action);
}
public <U> CompletableFuture<Void> thenAcceptBothAsync(
CompletionStage<? extends U> other,
BiConsumer<? super T, ? super U> action) {
return biAcceptStage(asyncPool, other, action);
}
public <U> CompletableFuture<Void> thenAcceptBothAsync(
CompletionStage<? extends U> other,
BiConsumer<? super T, ? super U> action, Executor executor) {
return biAcceptStage(screenExecutor(executor), other, action);
}
两个任务必须都完成,触发该任务。
thenCombine:组合两个 future,获取两个 future 的返回结果,并返回当前任务的返回值
thenAcceptBoth:组合两个 future,获取两个 future 任务的返回结果,然后处理任务,没有
返回值。
runAfterBoth:组合两个 future,不需要获取 future 的结果,只需两个 future 处理完任务后,
处理该任务。
8 两任务组合 - 一个完成
public <U> CompletableFuture<U> applyToEither(
CompletionStage<? extends T> other, Function<? super T, U> fn) {
return orApplyStage(null, other, fn);
}
public <U> CompletableFuture<U> applyToEitherAsync(
CompletionStage<? extends T> other, Function<? super T, U> fn) {
return orApplyStage(asyncPool, other, fn);
}
public <U> CompletableFuture<U> applyToEitherAsync(
CompletionStage<? extends T> other, Function<? super T, U> fn,
Executor executor) {
return orApplyStage(screenExecutor(executor), other, fn);
}
public CompletableFuture<Void> acceptEither(
CompletionStage<? extends T> other, Consumer<? super T> action) {
return orAcceptStage(null, other, action);
}
public CompletableFuture<Void> acceptEitherAsync(
CompletionStage<? extends T> other, Consumer<? super T> action) {
return orAcceptStage(asyncPool, other, action);
}
public CompletableFuture<Void> acceptEitherAsync(
CompletionStage<? extends T> other, Consumer<? super T> action,
Executor executor) {
return orAcceptStage(screenExecutor(executor), other, action);
}
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
Runnable action) {
return orRunStage(null, other, action);
}
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
Runnable action) {
return orRunStage(asyncPool, other, action);
}
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
Runnable action,
Executor executor) {
return orRunStage(screenExecutor(executor), other, action);
}
当两个任务中,任意一个 future 任务完成的时候,执行任务。
applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。
acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。
runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返
回值。
9 多任务组合
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
allOf:等待所有任务完成
anyOf:只要有一个任务完成