文章目录
一、初始化线程的4种方式
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口+FutureTask(可以拿到返回结果,可以进行异常处理)
- 线程池
- 继承Thread类和实现Runnable接口:主进程无法获取线程的运算结果。
- 实现Callable接口:主进程可以获取线程的运算结果,但是不利于控制服务器种的线程资源,可能导致服务器资源耗尽。
- 线程池:初始化方式
//初始化线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
二、new ThreadPoolExecutor()七大参数
- corePoolSize:线程池种一致保持的线程数量。
- maximumPoolSize:线程池种允许最大的线程数。
- keepAliveTime:当线程数大于核心线程数的时候,超出核心线程数的线程在最大多长时间没有接到新任务就会终止释放,最终线程池维持在corePoolSize大小。
- unit:时间单位。
- workQueue:阻塞队列,用来存储等待执行的任务,如果当前对线程的需求超过了corePoolSize大小,就会放在这里等待空闲线程来执行。
- threadFactory:创建线程的工厂,比如指定线程名等等。
- handler:拒绝策略。如果线程满了,线程池就会使用拒绝策略。
三、线程池运行任务的流程
1.流程
-
线程池创建,准备好core数量的核心线程,准备接受任务
-
新的任务进来,用core准备好的空闲线程执行。
1)core满了,就将再来的任务加入到阻塞队列种。空闲的core就会到阻塞队列中获取任务执行。
2)阻塞队列满了,就直接开新线程执行,最大只能开到max指定的数量。
3)max都执行好了。max-core数量空闲的线程就会在keepAliveTime指定的时间后自行销毁。最终保持到core的大小
4)如果线程开打max的数量,还是有新任务进来,就会使用reject指定的拒绝策略进行处理。 -
所有的线程创建都是由指定的threadFactory创建。
2.面试题
一个线程池 core=7;max=20;queue=50。那100个并发请求进来是怎么分配的?
先有7个请求能直接得到执行,接下来50个进入阻塞队列,在多开13(20-7)个线程继续执行请求任务。现在总过有7+13+50=70个任务被安排上了。剩余的30个默认执行拒绝策略。
四、常见的4种线程池
- newCacheThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,如无可回收,则新建线程。
- newFixedThreadPool:创建一个定长线程池,可以控制线程最大并发数,超出的线程回在队列种等待。
- newScheduledThreadPool:创建一个定长线程池,支持定时以及周期性任务执行。
- newSingleThreadExecutor:创建一个单线程的线程池,只会用唯一一个工作线程来执行任务,保证所有任务按照指定顺序执行。
五、CompletableFuture异步编排
在java8中,新增了一个包含50个方法左右的类,CompletableFuture,提供了非常强大的Future扩展功能,可以帮助简化异步编程的复杂性,提供了函数式编程的能力。可以通过回调的方式处理计算结果,并且提供了转换和组合CompletableFuture的方法。CompletableFuture类实现了Future接口,所以还是以通过get()方法阻塞或者轮询的方式获得结果。
1.CompletableFuture创建异步对象
CompletableFuture有四个静态方法来创建异步操作。
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
runAsync方法都是没有返回值的,supplyAsync都是可以获取返回结果的。
都可以传入自定义的线程池,否则就用默认的线程池。
2.计算完成时回调方法(whenComplete、exceptionally)
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 CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)
whenComplete可以处理正常和异常的计算结果,exceptionally处理异常情况。
whenComplete和whenCompleteAsync的区别:
- whenComplete:是执行当前任务的线程继续执行whenComplete的任务。
- whenCompleteAsync:把执行whenCompleteAsync的任务继续提交给线程池来执行。(可能开启新的线程。)
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture future = CompletableFuture.supplyAsync(new Supplier<Object>() {
@Override
public Object get() {
System.out.println(Thread.currentThread() + " ---- completableFuture");