为什么Thread实现Runnable?

Boa*_*ann 31 java runnable

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

我正在制作一个Thread的子类并重写run,我意识到我无法使该方法受到保护,因为Thread.run()是公共的.然后我意识到了原因:它必须是公共的,因为Thread实现了Runnable.但为什么它实现了Runnable?

这似乎不符合逻辑.一个线程是可启动的(来自当前线程),但是你没有像运行()一个Runnable(来自当前线程)那样运行它; 线程自己运行(在自己的线程上).如果你手动调用Thread的run方法,那么你不是将它用作Thread,只是一个重量级的Runnable.

由于这种设计,任何可以访问Thread对象的代码都可以调用它的公共运行方法,并可能潜入代码,这些代码不是公开的,或者设计为以这种方式调用.它还允许这样的非常奇怪的事情:

Thread.currentThread.run();
Run Code Online (Sandbox Code Playgroud)

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

Ste*_*n C 24

原因是"向后兼容".

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

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


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

这取决于你的"合法"的含义.

  • 早期写的旧代码并不是通过旧方式做事而"非法"的.关于它没有什么"破碎".

  • 可能的情况如果它确实是有意义的扩展Thread并重写run()方法.例如,您可能希望run()实现一些特殊的机制来将信息传入或传出提供的信息Runnable,或者实现一些特殊的异常处理,或者......使线程"可重启".

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

  • 无论是一个子类Thread,还是子类Runnable并将其赋予Thread的构造函数,都是无法阻止代码通过Thread.run公开调用的.另外,令人困惑的是,在Thread上有公共的`run()`和`start()`方法,并且调用错误的方法似乎仍然可行.此外,虽然我在添加内部类之后来到Java,但我没有看到它们的缺乏使得创建Thread的子类比运行Runnable的子类更容易. (2认同)
  • 好吧,我没有想到这个决定太老了.那么你会同意它从来没有真正合法或有用; 这只是一个历史性的失误?如果那是真的那么`Thread.run()`应该被标记为`@Derprecated`(这对覆盖它没有任何影响,但它至少会阻止人们通过直接调用它而不是`start()来滥用它. ,或者传递Threads就像它们是常见的Runnables一样). (2认同)
  • 不,不应该弃用.弃变是指对有害的事物.此外,在技术上不推荐在接口中定义的方法,而不在使用接口的*all*位置中弃用它.处理错误调用`run()`而不是`start()`的人的*right*方法是使用像PMD或Findbugs这样的工具. (2认同)