Java中有三种线程创建方式,分别为实现Runnable接口的run方法,继承Thread类并重写run的方法,实现Callable接口并用FutureTask封装的方式。
-
继承Thread类方式的实现:
package thread; //创建线程的第一种方式:继承Thread类方式 public class CreateThread01 { //继承Thread类并重写run方法 public static class MyThread extends Thread{ @Override public void run() { System.out.println("I am a child thread"); } } public static void main(String[] args) { //创建线程 MyThread thread = new MyThread(); //启动线程 thread.start(); } }
使用继承方式的好处是,在run()方法内获取当前线程直接使用this就可以了,无须使用Thread.currentThread()方法;不好的地方是Java不支持多继承,如果继承了Thread类,那么就不能再继承其他类。另外任务与代码没有分离,当多个线程执行一样的任务时需要多份任务代码,而Runable则没有这个限制。下面看实现Runnable接口的run方法方式。
-
实现Runnable接口的run方法方式:
//创建线程的第二种方式:实现Runnable接口的run方法方式 public class CreateThread02 { //实现Runnable的run方法 public static class RunableTask implements Runnable{ @Override public void run() { System.out.println("I an a child thread"); } } public static void main(String[] args) { RunableTask task = new RunableTask(); new Thread(task).start(); new Thread(task).start(); } }
在上面的代码中,两个线程公用一个task代码逻辑,如果需要,可以给RunableTask添加参数进行任务区分。另外,RunableTask可以继承其他类。
但是上面介绍的两种方式都有一个缺点,就是任务没有返回值。下面看最后一种,即使用FutureTask的方式。
- 实现Callable接口并用FutureTask封装的方式
//创建线程的第三种方式:使用FutureTask的方式
public class CreateThread03 {
public static class CallerTask implements Callable<String>{
@Override
public String call() throws Exception {
return "hello";
}
}
public static void main(String[] args) {
//创建异步任务
FutureTask<String> futureTask = new FutureTask<>(new CallerTask());
//启动线程
new Thread(futureTask).start();
try{
//等待任务执行完成,并返回结果
String result = futureTask.get();
System.out.println(result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
与 Runnable 相比,Callable 可以有返回值,返回值通过 FutureTask 进行封装。
小结:
使用继承方式的好处是方便传参,你可以在子类里面添加成员变量,通过set方法设置参数或者通过构造函数进行传递,而如果使用Runnable方式,则只能使用主线程里面被声明为final的变量。不好的地方是Java不支持多继承,如果继承了Thread类,那么子类不能再继承其他类,而Runable则没有这个限制。前两种方式都没办法拿到任务的返回结果,但是Futuretask方式可以。