Runnable的实现是否允许在同一个实例上并发调用run()?

Xåp*_* - 1 java concurrency multithreading software-design runnable

如果我有一个实现的类,java.lang.Runnable技术上没有什么能阻止多个线程run同一个实例上同时调用Runnable.例:

Runnable r = new MyRunnable();

//start thread 1
new Thread(r).start();

//start thread 2
new Thread(r).start();
Run Code Online (Sandbox Code Playgroud)

如果该run方法完全是"自包含的"(即不依赖于任何私有实例成员),这不是一个真正的问题,因为线程之间没有共享变量,因此您Runnable永远不会得到"损坏的"内部状态.但我认为,在大多数情况下,你Runnable 拥有它操纵在一些私人实例成员run,那么怎么办呢?

要使用示例,我的MyRunnable类有一个私有mode字段.主要目的是干净地停止run方法(通过设置modeSTOPPED),但它也有其他用途.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,如果我同时为同一个实例执行多个线程MyRunnable(如前所示),那么对它的任何更改都mode可能以不同的方式影响并发运行的线程.例如,如果一个线程设置了modeto STOPPED,另一个线程可能会mode在每个其他线程甚至看到它被设置为之前将其更改为其他线程STOPPED.这可以很容易地阻止线程退出while循环.

那么如何设计一个Runnable"可以同时使用"?它甚至可能吗?这不值得吗?是否有类似C#的ThreadStatic属性我可以使用(我认为在这种情况下它是完美的)?

Gra*_*ray 9

MyRunnable在这种情况下构建您的多个实例更为常见,而不是保护它们免受多次使用:

//start thread 1
new Thread(new MyRunnable()).start();
//start thread 2
new Thread(new MyRunnable()).start();
Run Code Online (Sandbox Code Playgroud)

使多个线程工作的全部目的是实现良好的并行计算.如果线程需要锁定公共资源(如工作队列等),那么很好但是编写你的Runnables以使它们"同时可用"不应该理所当然地做 - 应该有充分的理由这样做.

它甚至可能吗?

当然有可能.线程在它们之间的所有时间共享资源.但是在使用Mode mode变量的情况下,应该使用Runnable类的多个实例来完成.

如果多个线程正在调用公共代码,那么您可能会考虑使用一种模式ThreadLocal来存储每个线程的信息.但是,在多个实例中存储字段MyRunnableMyRunnable使用mode存储在a 中的一个实例更有效ThreadLocal.

这不值得吗?

如果这是在原则上完成的话,当然值得.同样,分叉线程的全部要点是让它们尽可能与其他线程分开以利用多个进程.