为什么线程实现可运行?

线程启动时,JVM会在该线程上调用Java线程的run()方法。 为了给线程做些什么,你可以创建Thread的子类并覆盖它的run()方法,或者(首选)你可以向线程的构造函数提供一个Runnable。 没关系。

我正在创建Thread的一个子类并重载运行,并且我意识到我无法按照预期保护该方法,因为Thread.run()是公共的。 然后我意识到了为什么:它必须是公开的,因为Thread实现了Runnable。 但为什么它实现Runnable?

这似乎不合逻辑。 一个线程可以从当前线程中启动,但不能像运行runnable(从当前线程)运行一样。 线程自己运行(在它自己的线程上)。 如果您手动调用Thread的run方法,那么您不会将它用作Thread,而只是一个重量级的Runnable。

由于设计原因,任何有权访问Thread对象的代码都可以调用其公共运行方法,并可能插入不打算公开或设计为以此方式调用的代码。 它也允许这样非常奇怪的事情:

Thread.currentThread.run();

线程实现Runnable是否有合法用途,我没有看到?


原因是“向后兼容”。

Thread类起源于Java 1.0 ...或更早版本。 在那些日子里,Java没有内部类,所以实现一个Runnable实例并不是一种轻量级的方式。 如果您查看那个时代的旧线程示例和教程,通常会看到扩展Thread并覆盖run()方法的类。

随着时间的推移,人们意识到扩展Thread并不是一个好主意(出于各种原因)。 但是, Thread设计无法更改,因为这会使旧的Java代码与新的JVM不兼容。


线程实现Runnable是否有合法用途,我没有看到?

这取决于你的意思是“合法的”。

  • 早期编写的旧代码由于以旧做法而不是“非法”的。 关于它没有任何“破碎”。

  • 有一些潜在的场景,它可以扩展Thread并覆盖run()方法。 例如,你可能想让run()实现一些特殊的机制来传递信息进出所提供的Runnable ,或者实现一些特殊的异常处理,或者......让线程“可重启”。

  • 甚至有可能你想直接在线程对象上调用run() 。 例如,如果你递交了一些延长Thread “狗早餐”代码,并且必须将其转换为在线程池中运行而不修改原始代码。 您可以考虑实例化crufty线程类并将实例作为runnables传递给线程池来运行。 (是的......太可怕了!)


  • 重写运行并不能解释为什么它需要公开。

    如果这是你的问题,我认为有一个简单的答案:执行接口的方法必须始终在java中公开。 用抽象类来保护它是可能的,但如果线程是抽象的,那么你将无法像这样使用它。

    至于为什么Thread首先实现Runnable,java必须知道线程实际上在哪个部分执行其工作。 他们使用run方法。 他们可以更清楚地分离刚刚实现Runnable的逻辑,并让Thread子类实现它,但这是我认为的一个小错误,由于历史原因难以改变。

    TLDR; AFAIK实际上并没有一个线程实现Runnable的好理由,但是它有这样的理由来实现某种类型的接口 - 它们应该可能只是有一些类似于ThreadRunnable的分离接口,而不是使用相同的接口还有其他用途的可运行界面。

    还要注意的是,在现代Java中,你应该使用Callables和FutureTasks而不是线程。 “整合超时,适当的取消和现代并发支持的线程池,对于我来说,要比成堆的原始线程更有用。”,引用了另一个在stackoverflow上的答案。

    链接地址: http://www.djcxy.com/p/16389.html

    上一篇: Why does Thread implement Runnable?

    下一篇: Notify() from runnable