Java单线程有三种实现方法
- 继承
Thread
类,重写run()
,无返回值 - 实现
Runnable
接口,重写run()
,无返回值 - 实现
Callable<V>
接口,重写call()
方法,有返回值
Java的单线程框架
这三种实现方式都是套用的一个线程框架,以下是简化的Thread
类源码:
// 线程任务定义接口
public interface Runnable {
public abstract void run();
}
// 线程类实现(源码简化版)
public class Thread implements Runnable {
private Runnable target;// 线程任务
public Thread() {
}
public Thread(Runnable target) {
this.target = target;
}
@Override
public void run() {
if (target != null) {
target.run();
}
}
public synchronized void start() {
start0();
}
// native方法由JVM底层C++实现,负责线程资源分配并启动
// 线程运行起来以后,会调用Java线程对象的run()方法执行线程任务
private native void start0();
}
第一种方法:继承Thread类
这种方法的实现原理是利用面向对象编程的三大特性之一:
继承
通过继承父类Thread
重写run()
方法,达到线程任务的具体化。
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("重写框架的线程任务调用逻辑");
}
public static void main(String[] args) {
new MyThread().start();
}
}
第二种方法:实现Runnable接口
这种方法才是单线程Thread
的框架本意,通过Thread
构造方法接收线程任务,然后运行自身定义好的run()
方法逻辑,执行线程任务。
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("实现具体的线程任务");
}
public static void main(String[] args) {
new Thread(() -> System.out.println("线程任务")).start();
}
}
第三种方法:实现Callable接口
这种方法与前两种方法最大的区别就是有返回值,启动线程并执行任务的代码途径与第二种方法一样,只是多了一层FutureTask
封装,而FutureTask
也是一个Runnable
的实现,多这一层的目的就是为了线程任务的返回值。
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("任务实现");
return "线程执行结果";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> task = new FutureTask<>(new MyCallable());
new Thread(task).start();
String result = task.get();// 阻塞当前线程,等待返回值
System.out.println(result);
}
}
task.get()
会阻塞当前线程,直到线程任务执行完毕,可以拿到返回值,或者线程任务执行出错,抛出异常。
至于task.get()
的阻塞原理,又是另一个问题了。