If I have a class that implements java.lang.Runnable, there is technically nothing stopping multiple threads from calling run concurrently on the same instance of the Runnable. Example:
Runnable r = new MyRunnable();
//start thread 1
new Thread(r).start();
//start thread 2
new Thread(r).start();
This is not really a problem if the run method is entirely “self-contained” (i.e. doesn’t rely on any private instance members), because there are no variables shared between threads, so your Runnable can never get a “corrupted” internal state. But I think in most cases, your Runnable will have some private instance members that it manipulates in run, so what to do?
To use an example, my MyRunnable class has a private mode field. The primary purpose is to cleanly stop the run method (by setting mode to STOPPED), but it has other uses as well.
public static class MyRunnable implements Runnable
{
enum Mode { RUNNING, PAUSED, STOPPED, FASTFORWARDING, REWINDING; }
private volatile Mode mode;
@Override
public void run()
{
mode = Mode.RUNNING;
while (mode != Mode.STOPPED)
{
//do stuff. possibly other changes to the mode.
}
}
public void setMode(Mode mode)
{
this.mode = mode;
}
public Mode getMode()
{
return mode;
}
}
As you can see, if I execute multiple threads concurrently for the same instance ofMyRunnable (like shown earlier), any change to the mode could affect concurrently running threads in different ways. For example, if a thread sets the mode to STOPPED, another thread might change the mode to something else before every other thread even gets to see that it was set to STOPPED. This could easily prevent threads from exiting the while loop.
So how do I design a Runnable to be “concurrently usable”? Is it even possible? Is it not worth it? Is there something like C#’s ThreadStatic attribute I can use (which I think would be perfect in this context)?
It is much more common to construct multiple instances of your
MyRunnablein this scenario as opposed to protecting them against multiple use:The whole purpose of having multiple threads working is to achieve good parallel computing. If the threads need to lock common resources (like work queues, etc.) then fine but writing your
Runnables to make them “concurrently usable” should not be done as a matter of course — there should be good reasons to do so.Certainly it is possible. Threads share resources all of the time between them. However in your case with the
Mode modevariable, this should be done with multiple instances of yourRunnableclass.If multiple threads are calling common code, one pattern you might consider is using
ThreadLocalto store per-thread information. But storing fields inside of multiple instances of yourMyRunnablewill be more efficient than having oneMyRunnableinstance with themodestored in aThreadLocal.It is certainly not worth it if this is done on principle. Again, the whole point of forking the threads is to have them be as separate as possible from other threads to utilize multiple processores.