ThreadFactory和newThread(Runnable r)如果是Thread的话,如何访问r的属性?

时间:2013-04-23 13:44:12

标签: java multithreading casting runnable executorservice

对于我的论文,我正在研究一个离散事件系统模拟器。模拟包含一组SimulatorThread extends Thread,其行动包括将Event安排到Simulator。每个SimulatorThread都会与SimulatorSimulatorInterface进行交互。

public abstract class SimulatorThread extends Thread {
    private SimulatorInterface si;

    public SimulatorThread(SimulatorInterface si) {
        this.si = si;
    }
    ...
}

public final class Simulator {
    private ExecutorService exec;
    ...

    public void assignThread(SimulatorThread... stList) {
        ...
    }
}

在模拟开始之前,每个SimulatorThread都分配给Simulator,然后Simulator将通过exec.execute(simulatorThread)执行每个线程。我的问题是在代码的某些部分我需要获得对当前运行SimulatorThread的引用,但是指令(SimulatorThread) Thread.currentThread()给出了一个强制执行。事实上System.out.print(Thread.currentThread().getClass())的输出是class java.lang.Thread,但我希望输出是class SimulatorThread,可以通过使用指令simulatorThread.start()运行线程而不是使用执行程序来获得。所以我认为问题在于编写一个返回ThreadFactory实例的 ad-hoc SimulatorThread

事实上我试图使用琐碎的SimulatorThreadFactory extends ThreadFactory

public class SimulatorThreadFactory implements ThreadFactory {

    @Override
    public Thread newThread(Runnable r) {
        return new SimulatorThread(new SimulatorInterface());
    }
}

并且通过这个我获得了之前引用的输出'class SimulatorThread'。问题是,当我调用'exec.execute(simulatorThread)'时,参数有一个属性'SimulatorInterface',我需要访问它,但我不能因为'newThread'方法的参数是'Runnable' ”。我在这里暴露了一个错误的代码,我希望表达的意思比我用文字解释的更好:

public class SimulatorThreadFactory implements ThreadFactory {

    @Override
    public Thread newThread(Runnable r) {
        SimulatorInterface si = r.getSimulatorInterface(); // this is what
                                                           // I would like
                                                           // the thread factory
                                                           // to do
        return new SimulatorThread(si);
    }
}

那么,如何在方法newThread内访问'SimulatorThread'的属性'SimulatorInterface',以便在SimulatorThread的参数为Runnable的情况下创建{{1}}?

2 个答案:

答案 0 :(得分:3)

如果我了解您的需求,正确的方法是扩展Thread,而是实施Runnable。然后,您可以享受您自己的类层次结构的所有好处:

public abstract class SimulatorRunnable extends Runnable {
     protected SimulatorInterface si;
     public SimulatorRunnable(SimulatorInterface si) {
         this.si = si;
     }
}

public final class Simulator extends SimulatorRunnable {
     public Simulator(SimulatorInterface si) {
         super(si);
     }
     public void run() {
         // here you can use the si
         si.simulate(...);
     }
}

然后将模拟器提交给线程池:

 Simulator simulator = new Simulator(si);
 ...
 exec.submit(simulator);
  

我的问题是在代码的某些部分我需要获取对当前运行的SimulatorThread的引用,但是指令(SimulatorThread)Thread.currentThread()给出了一个强制转换

您不应该将Thread传递给ExecutorService。它只是将它用作Runnable(因为Thread实现Runnable)并且线程池启动其自己的线程并且永远不会在{{1}上调用start() }}。如果您要延长SimulatorThread,则需要直接致电Thread将其提交至thread.start()ExecutorService implements Runnable的上述模式更好。

答案 1 :(得分:1)

@Gray的答案是正确的,指出ExecutorService旨在使用自己的线程来执行Runnables,有时创建的线程甚至会被重用来运行不同的Runnables。

试图从(SimulatorThread) Thread.currentThread()获取信息,就像'全局变量'反模式一样。最好在方法调用中传递'si'变量。

如果您确实需要线程安全的全局变量,请使用ThreadLocals:

public final class Simulator extends SimulatorRunnable {
    public static final ThreadLocal<SimulatorInterface> currentSim = new ThreadLocal<>();
    public Simulator(SimulatorInterface si) {
     super(si);
    }
    public void run() {
       currentSim.set(si)
       try{
          doStuff();
       }
       finally{
           currentSim.unset();     
       }
   }
   private void doStuff()
   {
      SimulatorInterface si = Simulator.currentSim.get();
      //.... 
   }
 }
相关问题