关于多线程上的相同Runnable引用

时间:2013-05-18 13:25:56

标签: java multithreading

当我们通过传递start()对象作为参数来调用线程上的Runnable时,我们是否可以传递相同的Runnable引用来启动多个线程?

public class MyMain {
    public static void main(String[] args) {
        MyRunnableImpl impl = new MyRunnableImpl();
        new Thread(impl).start();
        new Thread(impl).start();
    }
}

1 个答案:

答案 0 :(得分:7)

是的,您可以在Runnable相应实施后执行此操作。

但是你必须要小心你的Runnable实现不包含可变状态。您可以在自己的实现中控制它,但Runnable contract未指定。

// can be used for multiple Threads
class StatelessRunnable {
  public void run() {
    doSomething();
  }
}

// may go bang on the second execution -> use two instances
class StatefulRunnable {
  volatile boolean canRun = true;
  public void run() {
    if(!canRun) throw new IllegalStateException();
    canRun = false;
  }
}

在上面的示例中,您可以看到可以使用StatelessRunnable来获取任意数量的线程。事实上你甚至可以把它变成一个单身人士。相比之下,StatefulRunnable每个实例只能运行一次

共享状态

阅读Jon's answer我意识到可能存在实际想要共享两个Runnable实例的状态的情况。当然,有状态的Runnable实例并不总是会因多线程而失败,但这比无状态实例要复杂得多。

// willingly share state over threads
class WillinglyStatefulRunnable {
  final BlockingQueue<Object> sharedObjects = new BlockingQueue<Object>();
  public void run() {
    sharedObjects.offer(new Object());
  }
}

上面的示例显示了如何处理具有多个线程的单个集合sharedObjects

文学侧注

Joshau Bloch's Effective Java中的第15项说最小化可变性。本章 - 如果您有权访问该书 - 在更广泛的背景下解决类似的问题。简而言之,他指出,不可变对象使得重用实例和减少非法状态的可能性变得更加容易。