线程的四种实现方式:
引言:
方式一、继承Thread类
方式二、实现Runnable接口
方式三、实现Callable接口
方式四、通过线程池创建
接下来我就按照上面四种方式依次展开梳理
1.继承Thread类
Thread t1 = new Thread(){
//线程任务
public void run(){
}
}
这里我是通过匿名子类的方式进行简单的创建Thread对象,重写run()方法,run()方法其实就是具体要执行的线程任务。
2. 实现Runnable接口
通过实现Runnable接口,实现run()方法(线程任务)
class Task01 implements Runnable{
// 线程任务
public void run(){
}
}
class Main{
public static void main(String args){
Thread t2 = new Thread(new Task01());
t2.start();
}
}
3.实现Callable接口
前面两种创建Thread的方式,不论是继承Thread类、实现Runnable接口、重写的run()方法返回的值都是void,有时我们需要接收线程的任务的返回值,这时前两种创建方式都不合适。这样,我们可以通过实现Callable接口,来实现接收有返回值的线程任务。
class Task03 implements Callable<T>(){
// 线程的任务
public T call(){
}
}
这样我们就创建了线程的任务,但是Thread的有参构造方法中,没有根据Callable类型创建Thread对象
这时我们需要引入一个新的类FutureTask类,FutureTask实现类间接实现Runnable接口,于是我们可以将Callable类型的实现类封装成Runnable类型。
FutureTask futureTask = new FutureTask(Callable的实现类);
FutureTask futureTask = new FutureTask(new Task03());
获得了FutureTask对象,我们可以通过调用FutureTask对象的get()方法,获取线程任务call()方法的返回值
T ret = futureTask.get();
4.通过线程池的方式创建
创建线程池有两种方式:使用Executors线程池工具类创建线程池对象ExecutorService、创建自定义线程池对象ThreadPoolExecutor。
4.1Executors线程池工具类
线程池的分类
- FixedThreadPool:线程数固定的线程池
- CachedThreadPool:线程数根据任务动态调整的线程池
- SingleThreadExecutor:仅提供一个单线程的线程池
- ScheduledThreadPool:能实现定时、周期性任务的线程池
eg.创建一个固定数量的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new Runnable()); // 执行线程任务
Future f = executorService.submit(new Callable());
executorService.submit(new Callable);返回的类型为Future,通过调用Future对象的get();获取线程任务方法的返回值。
关闭线程池的方法
executorService.shutdown(); 等待当前正在运行的线程任务完成后关闭
executorService.shutdownNow();立即关闭线程池
调用shutdowm()方法,线程池对象不会立即关闭,会等待当前线程任务完成后关闭。所有我们可以每隔一段检查线程池的状态
while(!executorService.awaitTermination,1,TimeUnit.SECONDS);{
System.out.println("当前线程池还没关闭!");
}
!!! 注意,线程池使用完后,根据业务需求决定是否关闭。