创建一个线程,很多人会想到两种方式,一种是继承Thread类,一种是实现Runnable接口,如果需要返回参数,使用哪一种呢?现在就来说说三种不同的创建线程方式,以及它们的优缺点。
第一种方式,继承Thread类
/**
* 实现方式一:1.继承Thread类
* @author 程就人生
* @Date
*/
public class Thread1 extends Thread{
/**
* 重写run方法
*/
public void run() {
System.out.println("当前线程名称:" + Thread.currentThread().getName());
}
}
创建过程:
1.定义Thread类的子类,重写run方法;
2.创建Thread子类的实例;
3.调用该实例的start方法启动线程。
public static void main(String[] argo){
// 2.创建Thread子类的实例
Thread1 thread1 = new Thread1();
// 3.调用线程对象的start来启动该线程
thread1.start();
}
通过定义一个Thread的子类,创建一个线程对象,并调用start方法来启动线程对象,使用起来非常简单。
第二种方式,实现Runnable接口
/**
* 线程实现方式二:1.实现Runnable接口
* 线程任务类
* @author 程就人生
* @Date
*/
public class ThreadTarget implements Runnable{
private int i;
public ThreadTarget(int i) {
this.i = i;
}
/**
* 重写run方法
*/
@Override
public void run() {
System.out.println("当前线程名称:" + Thread.currentThread().getName() + ", i=" + i);
}
}
创建过程:
1.定义Runnable接口的实现类,重写run方法,作为线程任务类;
2.创建Runnable实现类的实例,并以该实例为target创建线程实例;
3.调用线程实例的start方法启动线程。
public static void main(String[] argo){
// 3.创建Runnable实现类的实例,它是线程对象运行的target
ThreadTarget threadTarget = new ThreadTarget(1);
// 该Thread对象才是真正的线程对象
Thread thread = new Thread(threadTarget);
// 4.调用线程对象的start来启动该线程
thread.start();
// 共享成员变量
new Thread(threadTarget).start();
}
如果线程任务类里有实例变量,那么多个线程可以共享这些实例变量。
特点:多个线程可以使用一个线程任务类,并且共享该类中的实例变量。
第三种方式,实现Callable接口
import java.util.concurrent.Callable;
/**
* 线程实现方式二:1.实现Callable接口
* @author 程就人生
* @Date
*/
public class ThreadCall implements Callable<Integer>{
/**
* 2.重写call方法
*/
@Override
public Integer call() throws Exception {
System.out.println("当前线程名称:" + Thread.currentThread().getName());
return 1;
}
}
创建过程:
1.定义Callable接口的实现类,并重写call方法;
2.创建Callable实现类的对象,使用FutureTask包装该对象,并以此为target创建线程对象;
3.调用线程对象的start方法启动该线程对象;
4.通过FutureTask包装对象获取返回值。
public static void main(String[] argo){
try {
// 3.创建Callable对象
ThreadCall call = new ThreadCall();
// 4.使用FutureTask来包装Callable对象
FutureTask<Integer> futureTask = new FutureTask<Integer>(call);
// 该Thread对象才是真正的线程对象
Thread thread3 = new Thread(futureTask);
// 4.调用线程对象的start来启动该线程
thread3.start();
System.out.println("有返回值的线程,返回值为:" + futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
特点:call方法比run方法更强大,可以设置返回值;Callable接口有泛型限制,可以控制返回值的类型。
最后总结
本文简单列举了三种创建线程对象的方式。第一种最简单,定义一个Thread子类,直接创建一个线程对象。第二种稍微复杂一点,粒度又细了一点,定义一个实现Runnable接口的线程任务类,在这个线程任务类的基础上,创建一个或多个线程,多个线程之间可以共享线程任务类的实例。第三种最复杂,定义一个实现Callable泛型接口的任务实现类,通过FutureTask包装,在此基础上创建一个或多个线程,每个线程都可以有返回值。具体使用哪种,还要看实际的业务场景。
网友评论