【问题标题】:Why it's not possible to get the Runnable embedded in a Thread?为什么无法将 Runnable 嵌入到线程中?
【发布时间】:2012-05-14 05:51:38
【问题描述】:

据我所知,从 java.lang.Thread 文档和 stackoverflow 上发布的其他问题(例如“How to access a Runnable object by Thread?”和“Get current instance of Runnable”)无法获得 Runnable 对象的引用嵌入Thread。

这种可能性很有用的一个场景是在实现一个方法时,它的签名不能被修改,因为我们正在覆盖另一个类或接口中定义的方法,并且需要根据类型执行不同的操作的Runnable 嵌入当前Thread。

如果我们在 Thread 类中有一个名为 getRunnable 的方法,我们可以这样做:

if (Thread.currentThread().getRunnable() instanceof Type1) {
  // do something...
} else {
  // do something else...
}

这在我们希望确保方法中包含的操作仅由某些线程执行而不由其他线程执行的情况下也很有用。

所以我想知道,Java 开发人员决定不允许从 Thread 获取 Runnable 实例是否有特定原因,或者它是否是一个值得通知的缺失功能?如果您认为该选择没有任何理由,但不值得将其通知为缺少功能,那么您会在上述场景中使用什么策略?

【问题讨论】:

  • 使用main 方法的主线程的“可运行”是什么?
  • 像您在示例中所做的那样在 instanceof 的结果上进行分支几乎不是一个好主意。
  • 我不会提供这个作为答案,因为它会很密集,但是嘿。您可以查看使用线程堆栈跟踪。 Thread.currentThread().getStackTrace().
  • 我不知道原因,但是您也可以扩展 Thread 类,并在您的子类中保留对 Runnable 对象的引用,并在需要时提供 getter 方法来获取 Runnable。
  • 并非所有Thread 实例都有可运行文件,不是吗?

标签: java multithreading concurrency runnable


【解决方案1】:

所以我想知道,Java 开发人员决定不允许从 Thread 获取 Runnable 实例是否有特定原因

这可能不是必需的。 Runnable 本身应该能够识别自己的类,因此它需要获取该信息的想法很奇怪。它也可以是一种保护,使其他线程无法访问在另一个线程中运行的类。

如果您需要从应用程序的其他部分访问当前的Runnable,那么我建议您使用ThreadLocal<Runnable>。在您的 run() 方法中,您可以设置它,然后在其他类中检索它。但是,您需要将 ThreadLocal 放在全局可访问的位置。

您还可以处理当前堆栈跟踪以找出封闭的 Runnable 类,这更像是一种 hack,但它会起作用。

【讨论】:

    【解决方案2】:

    有几种方法可以解决这个问题:

    将您的Runnables 映射到正在执行它们的Threads(使用Map<Thread, Runnable> 或ThreadLocal<Runnable>)
    使用反射从Thread访问Runnable:

    private static final Field target;
    static {
        Field f = null;
        try {
            f = Thread.class.getDeclaredField("target");
            f.setAccessible(true);
        } catch (NoSuchFieldException e) {
            // might happen in a different version of Java (works in Java 7)
            e.printStackTrace();
        }
        target = f;
    }
    
    public static Runnable getTarget(Thread t) {
        try {
            return (Runnable) target.get(t);
        } catch (IllegalAccessException e) {
            // shouldn't happen, we already made the field accessible when we created it
            e.printStackTrace();
            }
        return null;
    }
    

    【讨论】:

      【解决方案3】:

      有一个间接方法可能会有所帮助,您可以获取堆栈跟踪。

      StackTraceElement[] stackTraceElement = thread.getStackTrace();
      for(StackTraceElement e :stackTraceElement){
         System.out.println("Trace "+e.getClassName());
      }
      

      输出:

      跟踪 java.lang.Thread

      跟踪 com.emc.multithreading.RunnableDemo

      跟踪 java.lang.Thread

      【讨论】:

        猜你喜欢
        • 2017-09-04
        • 2018-12-31
        • 1970-01-01
        • 2011-08-27
        • 2013-06-29
        • 1970-01-01
        • 2018-08-03
        • 2012-06-16
        • 1970-01-01
        相关资源
        最近更新 更多