当我们通过传递start()
对象作为参数来调用线程上的Runnable
时,我们是否可以传递相同的Runnable
引用来启动多个线程?
public class MyMain {
public static void main(String[] args) {
MyRunnableImpl impl = new MyRunnableImpl();
new Thread(impl).start();
new Thread(impl).start();
}
}
答案 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项说最小化可变性。本章 - 如果您有权访问该书 - 在更广泛的背景下解决类似的问题。简而言之,他指出,不可变对象使得重用实例和减少非法状态的可能性变得更加容易。