概述
前面几篇博客主要从宏观角度上介绍了多线程有关的知识。本篇从实际应用角度介绍在JAVA代码中如何创建并启动线程。
Java 创建线程
本篇主要从以下三个模块介绍:
- JAVA 创建线程的三种方式
- 在实际应用中如何选择
- run() 方法和 start() 方法
1、 JAVA 创建线程的三种方式
在JAVA代码中有以下创建线程的方式:
- 继承 Thread 类
- 实现 Runnable 接口
- 实现 Callable 接口
1-1、继承 Thread 类
线程在JAVA代码中通过Thread类封装,因此我们只需要继承该类就可以实现一个自定义的线程类。具体代码如下:
private class Thread1 extends Thread {
@Override
public void run() {
System.out.println("通过继承创建的线程已启动");
}
}
@Test
public void test1() {
Thread1 thread1 = new Thread1();
thread1.start();
}
在上述代码中,我们编写 Thread1 类继承 Thread 转为线程类,当我们调用该类对象的 start() 方法后,控制台会打印出 “通过继承创建的线程已启动” 等信息,也就是说线程启动成功。
我们可以把 run() 方法理解为线程的执行体,线程启动后将会从 run() 方法开始执行。
1-2、实现 Runnable 接口
除了继承 Thread 类外,我们也可以通过实现 Runnable() 接口的方式来实现线程的执行体,并将该对象作为参数创建 thread 对象即可。具体代码如下:
private class Thread2 implements Runnable {
@Override
public void run() {
System.out.println("通过实现Runnable接口创建的线程已启动");
}
}
@Test
public void test2() {
Thread thread = new Thread(new Thread2());
thread.start();
}
当我们执行 thread 对象的 start() 方法,控制台将会打印“通过实现Runnable接口创建的线程已启动”
1-3、实现 Callable 接口
实现 Callable 接口和实现 Runnable 接口类似,只不过实现 Callable 接口可以获得线程体执行完毕的返回值,具体代码如下:
private class Thread3 implements Callable {
@Override
public Object call() throws Exception {
System.out.println("通过实现Callable接口创建的线程已启动");
return new String("我是返回值");
}
}
@Test
public void test3() throws ExecutionException, InterruptedException {
FutureTask futureTask = new FutureTask(new Thread3());
new Thread(futureTask).start();
System.out.println(futureTask.get().toString());
}
运行上述测试方法,控制将会输出“通过实现Callable接口创建的线程已启动”和“我是返回值”。
2、在实际应用中如何选择
首先,如果想要获取线程执行完毕的返回值,那么肯定是通过实现 Callable 接口类实现。
在继承 Thread 类还是实现 Runnable 接口的选择上,我是这样理解的:两者区别不是很大,但就我本人而且,我更倾向于 实现 Runnable 接口来实现,具体原因有以下两点:
-
java代码中每个类只能有一个父类,使用 Runnable 接口实现可以通过继承的方式统一封装部分公共属性和方法,使业务代码更整洁,而 继承 Thread 类就不行。
-
线程池可以有效管理实现了 Runnable 接口的对象,它通过一个线程同时执行多个实现Runnable 接口的方式来实现线程的复用,如果通过继承 Thread的方式来实现,那么就会复杂很多。这也正是线程池中线程能够复用的原理。
3、run() 方法和 start() 方法
run() 方法和 start() 方法是 JAVA 线程中最容易搞混的一个点。
创建一个线程并启动它是通过 start() 方法而不是 run() 方法。虽然执行 run() 方法也可以达到相同的效果,但是 run() 方法是在当前线程中调用对象方法来实现,而 start() 方法才是通过启动新线程,在新线程中执行线程体,两者有本质的差别。