Java多线程的实现方式到底有几种?网上和书籍中的说法鱼龙混杂,其实多线程的实现方式只有两种,分别是继承Thread类与实现Runnable接口。oracle官方文档中Thread类也明确了实现多线程的方式只有两种。
实现Runnable接口
1 |
|
继承Thread类
1 |
|
两种方法的对比
Runnable相比Thread存在明显的优点:
- 从代码架构角度:具体的任务(run方法)应该和“创建和运行线程的机制(Thread类)”解耦,用runnable对象可以实现解耦。
- 使用继承Thread的方式的话,那么每次想新建一个任务,只能新建一个独立的线程,而这样做的损耗会比较大(比如重头开始创建一个线程、执行完毕以后再销毁等。如果线程的实际工作内容,也就是run()函数里只是简单的打印一行文字的话,那么可能线程的实际工作内容还不如损耗来的大)。如果使用Runnable和线程池,就可以大大减小这样的损耗。
- 继承Thread类以后,由于Java语言不支持双继承,这样就无法再继承其他的类,限制了可扩展性。
实现Runnable接口并传入Thread类和继承Thread类然后重写run()在实现多线程的本质上,并没有区别,都是最终调用了start()方法来新建线程。这两个方法的最主要区别在于Thread类中run()方法的内容:
1 |
|
从run()方法的实现我们可以看出:实现Runnable接口最终调用target.run(),而继承Thread类run()方法整个都被重写。但是我们同时使用这两种方式会怎么样?代码如下:
1 |
|
结果只会打印”我来自Thread”,因为Thread类中的run()方法已经被重写了,所以不会执行Runnable类的run()方法了。
总结
我们只能通过新建Thread类这一种方式来创建线程,但是类里面的run方法有两种方式来实现,第一种是重写run方法,第二种实现Runnable接口的run方法,然后再把该Runnable实例传给Thread类。除此之外,从表面上看线程池、定时器等工具类也可以创建线程,但是它们的本质都逃不出刚才所说的范围。