我到处都读过,如果一个字段由不同的线程同时使用,则需要某种同步,如果它只被一个线程使用,则不需要它。但是,如果它被不同的线程使用,但不能同时使用呢? 我们来看一下这样的代码:
Thing thing = new Thing();
Thread t1 = new Thread(new MyRunnable(thing));
Thread t2 = new Thread(new MyRunnable(thing));
t1.start();
t1.join();//Wait for t1 to finish
t2.start();
MyRunnable是:
class MyRunnable implements Runnable {
//skipped constructor and field "private final Thing thing"
public void run() {
thing.someUpdate();
}
}
安全吗?是否由t2显示t1所做的所有更新?
答案 0 :(得分:9)
在这种情况下,更改是可见的,因为Thread.join
和Thread.start
创建了两个线程中的操作之间的关系。见Memory Consistency Errors:
当一个语句调用Thread.start时,每个语句都有一个 发生 - 在与该陈述的关系也有一个 发生在与新执行的每个语句的关系之前 线。导致创建新代码的代码的影响 线程对新线程可见。
当一个线程终止并导致另一个线程中的Thread.join时 return,然后终止线程执行的所有语句都有 与之后的所有陈述发生关系 成功加入。现在可以看到线程中代码的效果 到执行连接的线程。
如果您没有按此顺序使用这些方法,则可能无法看到更改。线程不需要同时运行以引起问题,因为值可以缓存在线程中,或者可能发生某些优化等。
答案 1 :(得分:1)
我认为这个问题太抽象了。问题的一般答案" t1所做的所有更新是否由t2显示?"是"是"。但它们只会因为你运行线程的方式而可见。示例中的线程不是并行的。所以,是的,在这个例子中,两个线程都可以看到MyRunnable的字段。但是MyRunnable类本身并不是线程安全的。如果它将与并发线程一起使用,你可能会 麻烦。 这取决于MyRunnable.someUpdate()的细节。你应该使用" volatile"您的字段的关键字," java.util.concurrent。*"如果需要,可以使用类或任何同步机制。 也许这个文档将有助于开始:https://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html
答案 2 :(得分:0)
在你的情况下它是安全的,因为两个线程没有在同一时间运行。
答案 3 :(得分:0)
join()
方法是一种阻止方法,等待线程完成。 t2应该看到t1的所有更新。
答案 4 :(得分:0)
在这种情况下它是安全的。事物对象上的t1所做的更改将对t2可见。如果没有t1.join();代码不是线程安全的。
t1.start();
t1.join();//Wait for t1 to finish
t2.start();