写在前面
这两个一直放在一起比较,网上太多文章,关键有很多错误的,都是抄来抄去。
比如这篇文章我就觉得讲的不好,可以看评论区小白猿疼疼的评论,Runnable是只实例化一个类对象,开启三个线程去运行,而Thread是实例化三个类对象,在java中创建启动线程的唯一方法是调用它的start方法。 可以发现作者其实也没真正搞明白。关于文中的一个观点:实现Runnable可以资源共享,给出的代码例子并不能论证,或者说论证的不好。
Runnable
在实际应用中,都是建议多使用Runnable,主要原因还是在于其灵活性(flexibility),并不专注于线程的行为,只是让它运行。借鉴这篇博客中的一段话: 其他还有一些面向对象的思想,Runnable就相当于一个作业,而Thread才是真正的处理线程,我们需要的只是定义这个作业,然后将作业交给线程去处理,这样就达到了松耦合,也符合面向对象里面组合的使用,另外也节省了函数开销,继承Thread的同时,不仅拥有了作业的方法run(),还继承了其他所有的方法。综合来看,用Runnable比Thread好的多.
另外,Runnable是一个接口,我们都知道java只支持单继承,所以使用Runnable更符合java的哲学:Inherit less, interface more.
如果学的更深一些,会发现后面诸如FutureTask、 ThreadPoolExecutor等传递的都是Runnable对象。
Thread
很多博客将资源共享作为Runnable的优点之一,很明显太片面,因为Thread也可以资源共享,因为Thread本来就是实现了Runnable,包含Runnable的功能是很正常。
两者不宜非要比较不同
为这么这么说?因为这两者是相互依赖的,只实现Runnable接口是没法使用多线程的,因为没有start方法,还是要用Thread包装,两者的关系就像汽车的车轮和发动机一样。
实现接口Runnable时,意味着创建了可在不同线程中运行的对象(共享的原因),创建了一个可以在线程中运行的东西,不意味着创建了一个线程。可以说实现了Runnable接口的类只是一个带有run方法的普通类。如果不将其传递给Thread,其也不过只是带有run普通方法的普通对象。
Thread具有启动一个新线程的能力,通过其start方法实现了多线程。
对于实现多线程,可以简单来说需要两样东西:
- 可以运行在线程中的东西(Runnable)
- 可以启动一个线程的东西(Thread)
所以两者是必须的,像汽车启动需要发动机和车轮一样。因此,无法只用Runnable启动线程,而需要将其传递给一个Thead实例。
有人可能会疑问:不用Runnable,只用Thread也可以启动多线程啊。
这个前面已经说过了,因为Thread实现了Runnable,所以Thread也是一个Runnable。