多线程(multithreading),是指从硬件或软件上实现多个线程并发执行的技术。
一、Java多线程的实现方式主要有四种
Java多线程的实现方式有:继承Thread类、实现Runnable接口、实现Callable接口通过FutureTask包装器来创建Thread线程、使用ExecutorService和Callable以及Future实现有返回结果的多线程
1.继承Thread类
Thread类是Runnable接口的一个实现类,代表线程的一个实例。我们实现多线程的时候,可以通过继承Thread类,执行run()方法实现多线程。
从上面这两种输出结果可以看出:start()方法输出的结果不一样,这是因为start()方法中含有run()方法,start()方法会创建一个新的线程进行启动;而run()方法直接启动当前线程
注意:由于Java的特性,如果自己的类已经继承了其他的类(例如上面的例子中Sync类继承了其他的类,则不能再继承Thread类),就无法再继承Thread类,则该种实现多线程的方式就不能再使用。
2.实现Callable接口通过FutureTask接口包装器来创建Thread线程
如果自己的类已经继承了其他的类,则可以实现一个Runnable接口(由于Java一个类可以实现多个接口,则不存在方式1的问题)。例如:
从上面的实例中可以知道:为了启动SyncThread,首先需要实例化一个Thread对象,然后传入自己的SyncThread实例。事实上,当传入一个Runnable的实现类对象给Thread后,Thread的run()方法会调用Runnable的实现类对象的run()方法,参考JDK源代码。
3.实现Callable接口通过FutureTask包装器来创建Thread线程
3.1 Callable接口介绍
①java.util.concurrent.Callable是一个泛型接口,只有一个call()方法
②call()方法抛出Exception异常,且返回一个指定的泛型类对象
3.2 Callable接口实现多线程的应用场景
当父线程想要获取子线程的运行结果
3.3 使用Callable接口实现多线程的步骤
①创建Callable子类的实例化对象
②创建FutureTask对象,并将①传入FutureTask对象中【FutureTask类实现了Runnable接口和Future接口】
③创建Thread对象,并将②传入Thread对象中
④启动线程
例如:
4.使用ExecutorService和Callable以及Future实现有返回结果的多线程【线程池的方式】
ExecutorService接口和Callable接口以及 Future接口都是属于EXecutor框架
4.1 Executor框架
Executor框架是在Java1.5中引入的,它把任务的提交和执行进行解耦,只需要将写好的任务方法交给线程池就行了。例如:
其中:①表示的是初始化包含10个线程的Executor线程池;②表示的是调用线程池中的线程来执行任务
4.2 可返回值的任务必须实现Callable接口,无返回值的任务必须实现Runnable接口
执行Callable任务后,可以获取一个Future的对象,在该对象调用get就可以获取当Callable任务返回的Object对象了
其中:get方法是阻塞的,即:线程无返回结果,get方法会一直等待
再结合线程池接口ExecutorService就可以实现有返回结果的多线程了。
例如:
package com.peng.demo.sync;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class SyncThread{
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("程序开始执行");
Date date = new Date();
//创建含有5个线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//用来储存返回值结果
List> list = new ArrayList>();
for(int i = 0; i < 10; i++){
Callable
程序运行结果:
程序开始执行
0任务启动
1任务启动
2任务启动
3任务启动
4任务启动
5任务启动
6任务启动
7任务启动
8任务启动
9任务启动
4任务终止
3任务终止
0任务终止
7任务终止
5任务终止
2任务终止
0执行的任务时间【1000】毫秒
6任务终止
1任务终止
1执行的任务时间【1000】毫秒
2执行的任务时间【1000】毫秒
8任务终止
9任务终止
3执行的任务时间【1000】毫秒
4执行的任务时间【1000】毫秒
5执行的任务时间【1000】毫秒
6执行的任务时间【1000】毫秒
7执行的任务时间【1000】毫秒
8执行的任务时间【1000】毫秒
9执行的任务时间【1000】毫秒
程序结束运行,运行时间为【1005】毫秒