Java创建线程的方式
一些创建线程的方式
如何创建线程
一般来说,创建线程有很多种方式,例如继承Thread
类、实现Runnable
接口、实现Callable
接口、使用线程池、使用CompletableFuture
类等等。
不过,这些方式其实并没有真正创建出线程。准确点来说,这些都属于是在 Java 代码中使用多线程的方法。
严格来说,Java
就只有一种方式可以创建线程,那就是通过new Thread().start()
创建。不管是哪种方式,最终还是依赖于new Thread().start()
。
继承Tread类
这是最普通的方式,继承Thread
类,重写run
方法,如下:
1 | public class ExtendsThread extends Thread { |
实现Runnable接口
这也是一种常见的方式,实现Runnable
接口并重写run
方法,如下:
1 | public class ImplementsRunnable implements Runnable { |
与继承Thread
接口不同的是,Java当中是单继承,当一个类继承了Thread
类后就无法再继承其他的类,通过实现Runnable
接口并重写run
方法,可以再实现继承其他类。
实现Callable接口
和上一种方式类似,这里需要去重写Callable
接口的call
方法,并配合FutureTask
使用,只不过这种方式可以使用get()
方法拿到线程执行完的返回值,如下:
1 | public class ImplementsCallable implements Callable<String> { |
使用ExecutorService线程池
这种属于进阶方式,可以通过Executors
创建线程池,也可以自定义线程池,如下:
1 | public class UseExecutorService { |
注意点
创建线程的方式十分多样,最少都能有上面的四种答案,那这真的对吗?可以说对,但严格意义上来说,又不对。
抛开后面一些先不谈,咱们就聊最开始的三种:“继承Thread
类、实现Runnable
接口、实现Callable
接口”,这应该是广为人知的答案。
那么此时来看个例子:
1 | public class ImplementsRunnable implements Runnable { |
这里定义了一个类,实现了Runnable
接口并重写了run
方法,按前面的说法,这种方式是不是创建了一条线程?答案是Yes
,可问题来了,请你告诉我,该如何启动这条所谓的“线程”呢?
1 | public static void main(String[] args) { |
难道像上面这样嘛?来看看运行结果:
1 | main:小猫爱吃鱼 |
结果很显然,打印出的线程名字为:main
,代表目前是主线程在运行,和调用普通方法没任何区别,那究竟该如何创建一条线程呀?要这样做:
1 | public static void main(String[] args) { |
先new
出Runnable
对象,接着再new
一个Thread
对象,然后把Runnable
丢给Thread
,接着调用start()
方法,此时才能真正意义上创建一条线程,运行结果如下:
1 | Thread-0:小猫爱吃鱼 |
此时线程名字变成了Thread-0
,这意味着输出“小猫爱吃鱼”这句话的代码,并不是main
线程在执行了,实现了Runnable
接口的ImplementsRunnable
类,并不能被称为一条线程,包括所谓的Callable、FutureTask……
,都不能创建出真正的线程。
换到前面所提出的三种方式中,只有继承Thread
类,才能真正创建一条线程,如下:
1 | public class ExtendsThread extends Thread { |
因为当你用一个类,继承Thread
类时,它内部所有的方法,都会被继承过来,所以当前类可以直接调用start()
方法启动,更具体点来说,在Java
中,创建线程的方式就只有一种:调用Thread.start()
方法!只有这种形式,才能在真正意义上创建一条线程!