-
一 、继承Thread类创建
- 通过继承Thread类,重写其run方法,run()为线程要执行的任务,因此又称为执行体。
- 创建Thread的子类的实例,创建线程对象,调用start()方法启动线程
(线程类已经继承Thread类,则无法继承其他类;每个线程都需要创建不同的Thread类,多个线程间无法共享线程类的实例变量)
public class HelloWorldThread extends Thread{
@Override
public void run() {
System.out.println("Hello world!");
}
public static void main(String[] args) {
Thread thread = new HelloWorldThread();
thread.start();
}
}
-
二、通过实现Runnable接口创建
- 创建Runnable接口的实现类,重写该接口的run()方法
- 创建Thread对象,同时创建实现类的实例作为Thread的target,调用start()方法启动线程
(Thread对象是真正的线程,实现类只是线程的执行体)
public class HelloWorldThread implements Runnable{
@Override
public void run() {
System.out.println("Hello world!");
}
public static void main(String[] args) {
Thread thread = new Thread(new HelloWorldThread());
thread.start();
}
}
-
三、通过Callable和Future创建线程
继承Thread类和实现Runnable的方式没有返回值,也无法抛出异常,如何判断线程是否执行完成,了解任务执行情况,取消任务的执行,这就需要Callable和Future来创建线程
- 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
- 使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
- 使用FutureTask对象作为Thread对象的target创建并启动新线程。
- 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
Callable类似于Runnable接口的增强版,其提供的call()方法将作为线程的执行体,同时允许有返回值。但是Thread类的target参数是Runnable类型。
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
这时就需要借助 Future接口,此接口可以接受call() 的返回值,RunnableFuture接口是Future接口和Runnable接口的子接口,可以作为Thread对象的target ,并且, Future 接口提供了一个实现类:FutureTask 。
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
FutureTask实现了RunnableFuture接口,可以作为 Thread对象的target。
public class CallableTest implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Random random = new Random();
Integer add = 0;
for (int i = 0; i < 100; i++) {
add = add + i;
}
System.out.println("CallableTest:" + add);
return add;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask = new FutureTask<>(new CallableTest());
Thread thread = new Thread(futureTask);
thread.start();
System.out.println(futureTask.get());
}
}
FutureTask是一个包装器,使用FutureTask类来包装Callable对象,它通过接受Callable来创建,调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
最后我们来分析下Future接口
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
- cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
- isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
- isDone方法表示任务是否已经完成,若任务完成,则返回true。
- get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回。
- get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。