【问题标题】:Why is the java.lang.Thread class in Java not marked final by the designers?为什么Java中的java.lang.Thread类没有被设计者标记为final?
【发布时间】:2011-07-23 16:05:21
【问题描述】:

当我们可以通过实现 Runnable 并将其传递给 Thread 构造函数来实现相同的功能时,允许用户通过扩展 Thread 类来创建线程的本质是什么。

【问题讨论】:

    标签: java multithreading language-design runnable library-design


    【解决方案1】:

    通过以下方式实现相同的功能 实现 Runnable 并将其传递给 线程构造函数

    扩展Thread的使用不限于Runnable。例如,您可以change the behavior of some methods 或添加您自己的线程本地信息(始终使用Thread.currentThread() 访问)。

    【讨论】:

      【解决方案2】:

      从历史的角度来看,您需要了解Thread API 是在 Java 1.0 中设计的,在 Java 支持匿名内部类之前。很多早期的示例代码都显示了Thread 的子类化。直到后来:

      • 他们增加了对匿名内部类 (Java 1.1) 的支持
      • 他们发现最好使用内部类(等)来提供 Runnable 实例
      • 他们实现了用于任务执行、线程池等的标准类 (Java 5.0)。

      “.Net 中的 Thread 类被标记为 final”是很好的说法,但你必须意识到 C# / .Net 在几年后出现......并且是能够学习Java的设计。 Java 曾经/现在被许多不太完美的设计决策的历史包袱所困……因为不破坏旧代码的压倒一切的必要性。

      【讨论】:

        【解决方案3】:

        Thread 的不寻常之处在于它可以引用Runnable 来运行,但它本身也是Runnable。默认情况下,Thread 将使用自己作为 Runnable 实例来运行,当然你可以将它指向其他地方。

        我认为没有充分的理由将Thread 标记为最终并需要外部Runnable 或使Thread 可扩展并使其成为自己的Runnable。两种方法都非常好,似乎没有一种比另一种更好。

        如果我不得不猜测,使Thread 成为子类的原因是它允许您编写这样的代码:

        Thread t = new Thread() {
            public void run() {
               /* ... your code here ... */
            }
        };
        

        这比创建Runnable 的子类然后将其包装在线程中要干净一些。同样,您可以从Thread 继承子类以获得Runnable,该Runnable 清楚地表明它应该用作线程。当然,这主要是一个美学问题,如果 Java 设计者采取相反的方式,我认为这将是一个非常好的决定。

        【讨论】:

        • 它在语法上更干净,但在设计上并不干净,并且在当前类加载器被卸载时(例如在应用服务器中)可能会产生严重的影响(perm gen泄漏)。
        • @Piotr,类垃圾和所有静态爵士乐,不幸的是,仅通过不覆盖线程将无法解决,即使在死线程上,CCL 也被保留为参考,仅此一项就足够了伤害。 inheritAccessControlContext 和 runnable 保持在正在运行的线程上,所以差别很大。
        • 覆盖线程有一些含义,比如跟踪危险的线程子类(例如覆盖 get/setContextClassLoader()),这会导致一些额外的操作和同步。 Thread.isCCLOverridden(Class)
        【解决方案4】:

        如果我可以添加一些东西,通过扩展 Thread,您可以拥有线程的扩展功能(Runnable 中不存在,因为它只包含 run() 方法),比如允许您的线程充当守护线程(就像垃圾收集器守护线程)。其他线程存在,例如调用类的 main 方法的单个非守护线程(当 JVM 启动时)。

        Runnable 接口允许您的类作为线程激活(通过实现run() 方法)。

        【讨论】:

          【解决方案5】:

          线程类描述线程如何运行,Runnable 描述运行什么。如果要修改运行的内容,则应实现 Runnable。如果你想修改线程的运行方式,你可以从 Thread 派生。如果您想修改线程的运行方式,您可以从 Thread 派生并实现一个单独的 Runnable 对象。

          【讨论】:

            【解决方案6】:

            我能想到的唯一好处是:如果你扩展 Thread 类,它会让你的 run() 方法被标记为受保护。 实现 Runnable 的一个缺点是您的 run 方法必须标记为公共。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-05-10
              • 2015-12-27
              • 2013-04-24
              • 2018-01-22
              • 2011-01-29
              • 2023-03-17
              • 2019-09-16
              相关资源
              最近更新 更多