Search code examples
javamultithreadingcastingrunnableexecutorservice

ThreadFactory and newThread(Runnable r) how to access to the attributes of r if it is a Thread?


For my thesis I'm working on a Discrete Event System Simulator. The simulation consists in a set of SimulatorThread extends Thread whose action consist in scheduling Events to the Simulator. Each SimulatorThread interracts with the Simulator through the SimulatorInterface.

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) {
        ...
    }
}

Before the simulation begins, each SimulatorThread is assigned to the Simulator, then the Simulator will execute each thread through exec.execute(simulatorThread). My problem is that in some part of the code i need to get a reference to the current running SimulatorThread, but the instruction (SimulatorThread) Thread.currentThread() gives a cast execption. Infact the output of System.out.print(Thread.currentThread().getClass()) is class java.lang.Thread, but I would like that the output is class SimulatorThread which can be obtained by running the thread using the instruction simulatorThread.start() instead of using the executor. So I thought that the problem is in writing an ad-hoc ThreadFactory that return an instance of SimulatorThread.

Infact I tried to use the trivial SimulatorThreadFactory extends ThreadFactory:

public class SimulatorThreadFactory implements ThreadFactory {

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

and with this I obtained the previously cited output 'class SimulatorThread'. The problem is that when I call 'exec.execute(simulatorThread)', the parameter has an attribute 'SimulatorInterface' to which I need to get access, but I can't becaues the parameter of the method 'newThread' is a 'Runnable'. I expose here a wrong code that I hope expresses what I mean better than how I explain in words:

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);
    }
}

So, how can I access to attribute 'SimulatorInterface' of the 'SimulatorThread' inside the method newThread in order to create a SimulatorThread if its paramater is a Runnable?


Solution

  • If I understand your needs, the right way to do this is to not extend Thread but to implement Runnable. Then all of the benefits of your own class hierarchy can be enjoyed:

    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(...);
         }
    }
    

    Then you submit your simulator to your thread-pool:

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

    My problem is that in some part of the code i need to get a reference to the current running SimulatorThread, but the instruction (SimulatorThread) Thread.currentThread() gives a cast execption

    You should not be passing a Thread into an ExecutorService. It is just using it as a Runnable (since Thread implements Runnable) and the thread-pool starts its' own threads and will never call start() on your SimulatorThread. If you are extending Thread then you need to call thread.start() directly and not submit it to an ExecutorService. The above pattern of implements Runnable with an ExecutorService is better.