零、前言
我的学习策略很简单,题海策略+ 费曼学习法。如果能把这100题都认认真真自己实现一遍,那意味着 JAVA语言 已经筑基成功了。后面的进阶学习,可以继续跟着我,一起走向架构师之路。
一、题目描述
题目:
Java创建线程的几种方式:
Java使用Thread类代表线程,所有线程对象都必须是Thread类或者其子类的实例。Java可以用以下5种方式来创建线程:
1)继承Thread类创建线程;
2)实现Runnable接口创建线程;
3)实现Callable接口,通过FutureTask包装器来创建Thread线程;
4)使用ExecutorService、Callable(或者Runnable)、Future实现由返回结果的线程。
5)使用CompletableFuture类创建异步线程,且是据有返回结果的线程。 JDK8新支持的
实现:使用这5种方式创建线程,体验其中的妙处。
二、解题思路
继承Thread类创建线程
Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extends Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。
实现Runnable接口创建线程
如果自己的类已经extends另一个类,就无法直接extends Thread,此时,可以实现一个Runnable接口
实现Callable接口,通过FutureTask包装器来创建Thread线程
实现一个Callable接口(它是一个具有返回值的)
使用ExecutorService、Callable(或者Runnable)、Future实现由返回结果的线程
Executors类,提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService接口:
//创建固定数目线程的线程池。
public static ExecutorService newFixedThreadPool(int nThreads) ;
//创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
public static ExecutorService newCachedThreadPool();
//创建一个单线程化的Executor。
public static ExecutorService newSingleThreadExecutor();
//创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize);
复制代码
ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。
使用CompletableFuture类创建异步线程,且是据有返回结果的线程
Future模式的缺点
Future虽然可以实现获取异步执行结果的需求,但是它没有提供通知的机制,我们无法得知Future什么时候完成。
要么使用阻塞,在future.get()的地方等待future返回的结果,这时又变成同步操作。要么使用isDone()轮询地判断Future是否完成,这样会耗费CPU的资源。
CompletableFuture介绍
JDK1.8新加入的一个实现类CompletableFuture,实现了Future, CompletionStage两个接口。
CompletableFuture中4个异步执行任务静态方法:
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return asyncSupplyStage(asyncPool, supplier);
}
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,Executor executor) {
return asyncSupplyStage(screenExecutor(executor), supplier);
}
public static CompletableFuture<Void> runAsync(Runnable runnable) {
return asyncRunStage(asyncPool, runnable);
}
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) {
return asyncRunStage(screenExecutor(executor), runnable);
}
复制代码
其中supplyAsync用于有返回值的任务,runAsync则用于没有返回值的任务。Executor参数可以手动指定线程池,否则默认ForkJoinPool.commonPool()系统级公共线程池
三、代码详解
第一种:继承Thread类创建线程
package com.xiaoxuzhu;
import java.util.concurrent.CountDownLatch;
/**
* Description:继承Thread类创建线程