一、基础知识
1、初始化线程的4种方式
1.1继承Thread类
public static class Thread01 extends Thread {
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10/2;
System.out.println("运行结果: " + i);
}
}
//调用
Thread01 thread01 = new Thread01();
thread01.start();
1.2实现Runnable接口
public static class Runnable01 implements Runnable {
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10/2;
System.out.println("运行结果: " + i);
}
}
Runnable01 runnable01 = new Runnable01();
new Thread(runnable01).start();
1.3实现Callable接口+FutureTask(可以拿到返回结果,可以处理异常)
public static class Callable01 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10/2;
System.out.println("运行结果: " + i);
return i;
}
}
//3)、实现 Callable 接口 + FutureTask (可以拿到返回结果,可以处理异常)
FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
new Thread(futureTask).start();
Integer integer = futureTask.get();
//等待整个线程执行完成,拿到返回结果 阻塞等待
1.4线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,
200,
10,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(200),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
/**
* newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
* newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
* newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
* newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务
* 按照指定顺序(FIFO, LIFO, 优先级)执行。
*/
七大参数
1、corePoolSize:核心线程数;线程池创建号后就准备就绪的线程数量【一直存在,除非 allowCoreThreadTimeOut 设置了】,就等待接受异步任务执行。
2、maximumPoolSize 最大线程数; 控制资源,
3、keepAliveTime 存活时间 。 如果当前正在运行的线程数量大于core , 释放空闲的线程【超过核心数的那一部分】,线程空闲大于指定的存活时间keepAliveTime。
4、unit 时间单位
5、workQueue 阻塞队列,如果任务有很多,就会将目前多的任务放在队列里面,只要有线程空闲了,就会去队列里面取新的任务执行 new LinkedBlockingDeque<>() 默认是 Integer的最大值。 太大了要自己指定
6、threadFactory 线程创建的工厂
7、handle 如果队列满了,应该怎么操作。 拒绝策略
流程
(1) 、core 满了,就将再进来的任务放入阻塞队列中。空闲的 core 就会自己去阻塞队
列获取任务执行
(2) 、阻塞队列满了,就直接开新线程执行,最大只能开到 max 指定的数量
(3) 、max 都执行好了。Max-core 数量空闲的线程会在 keepAliveTime 指定的时间后自
动销毁。最终保持到 core 大小
(4) 、如果线程数开到了 max 的数量,还有新任务进来,就会使用 reject 指定的拒绝策
略进行处理
一个线程池 core 7 max 20 queue 50 100并发进来怎么分配
7 个立即执行 50个进入队列 再开13个执行 30被拒绝
总结
1、2不能得到返回值,3可以获得返回值
1、2、3不能控制资源,4可以控制资源的使用
二、CompletableFuture异步编排
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果: " + i);
}, executorService);
//方法完成后的感知
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果: " + i);
return i;
}, executorService).whenComplete((res, ex) -> { //得到异常信息,但是没法修改结果
System.out.println("异步任务完成了......结果是:" + res + ";异常是:" + ex);
}).exceptionally(throwable -> {
return 10;//出现异常后,可以指定默认返回
});
//方法执行完成后的处理
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果: " + i);
return i;
}, executorService).handle((res, ex)->{
if (res != null) {
return res * 2;
}
if (ex != null) {
return 0;
}
return 0;
});
/**
* 两个任务只要有一个完成,就执行任务3
* runAfterEitherAsync 不感知结果,也没有返回值
*/
future1.runAfterEitherAsync(future2, () -> {
System.out.println("任务3开始");
}, executorService);
//两个任务都完成才执行任务3
future1.runAfterBothAsync(future2, () -> {
System.out.println("任务3开始");
} ,executorService);