Java线程创建方式
一般来说我们比较常用的有以下三种方式,下面介绍它们的使用方法。
1 继承Thread类
通过继承 Thread 类,并重写它的 run 方法,就可以创建一个线程。
1 |
|
使用继承方式的好处是,在run()
方法内获取当前线程直接使用this就可以了,无须使用Thread.currentThread()
方法;不好的地方是Java不支持多继承,如果继承了Thread
类,那么就不能再继承其他类。另外任务与代码没有分离,当多个线程执行一样的任务时需要多份任务代码
2 实现 Runnable 接口
实现Runnable
类,并实现其run()
方法,也可以创建一个线程。
1 |
|
Runnable
接口是一个被@FunctionalInterface
注解修饰,因此可以通过lambda表达式进行创建,因此使用Runnable
方式创建线程也可以通过下列方式进行简化:
1 |
|
3 实现 Callable 接口,并结合 Future 实现
首先,要定义一个Callable
实现类,并实现call
方法;其次,通过Future
的构造方法传入Callable
实现类的实例;然后,把FutureTask
作为Thread
类的 target ,创建 Thread
线程对象;最后,可以通过Future
的get
方法获取线程的运行结果。
1 |
|
总结
相比于第一种方式,更推荐第二种方式。因为继承继承
Thread
类往往不符合里氏代换原则,而实现Runnable
接口可以使编程更加灵活,对外暴露的细节较少,使用者只需要关注run()
方法的实现上;Runnable
和Callable
接口的定义如下:1
2
3
4
5
6
7
8
9
10
11// Runnable接口
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
// Callable接口
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}通过对比两个接口定义可知
Runnable
和Callable
有两点不同:(1)通过call
方法可以获取返回值。前两种方式在任务结束后,无法直接获取执行结果,只能通过共享变量获取,而第三种则可解决这一问题;(2)call
可以抛出要异常,Runnable
则需要通过setDefaultUncaughtExceptionHandler()
方法才能在主线程中获取子线程中的异常。
每创建一个线程,实际上会在虚拟机栈上创建一个新的栈。因为每个虚拟机栈都是线程私有的,因此各线程之间不会相互干扰。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!