我正在经历this tutorial并且它提到如果我们不同步这两行代码将会发生“不一致状态”。我试图重现这种“不一致的状态”,但我无法这样做。你能告诉我究竟什么是“不一致的状态”吗?
教程说,“myColorInt的值与myColorName的值不匹配”..但我似乎没有任何问题......你能解释一下他们试图避免的问题究竟是什么? / p>
答案 0 :(得分:1)
试图避免的情况称为竞争条件:
http://en.wikipedia.org/wiki/Race_condition
序列的结果
int myColorInt = color.getRGB(); //Statement 1
String myColorName = color.getName(); //Statement 2
对于在其他线程中执行的此代码线程,取决于 timing 。如果另一个线程在这两个语句之间设置颜色,则myColorName
中存储的名称将与myColorInt
中存储的颜色匹配。这就是教程所指的不一致状态。
同步用于对跨线程共享和访问可变数据的方式提供某些保证。这个块
synchronized (color) {
int myColorInt = color.getRGB();
String myColorName = color.getName();
}
使用同步来确保两个语句以原子方式执行;也就是说,防止另一个线程在这个线程位于两个语句之间时改变color
对象的状态(假设其他线程也正在使用同步)。
即使对于专家来说,并发和线程安全也可能很难实现。并发问题导致难以诊断,难以重现和零星的问题。由于您刚刚开始,我建议尽可能避免并发编程。否则,Brian Goetz等人的书 Java Concurrency in Practice 。人。是一个很好的开始。
答案 1 :(得分:0)
仅仅因为你没有看到这个问题并不意味着它不会发生。但是,它可能会发生,并可能会在某些时候发生。这实际上意味着无法保证这些线程运行的结果,并且没有保证您无法确定您的代码将执行什么操作。解决方案是将其放在synchronized
块
答案 2 :(得分:0)
我想你的意思是你链接到的网站的这一行,如果省略同步,可能会导致“不一致的状态”:
synchronized (color) {
int myColorInt = color.getRGB();
String myColorName = color.getName();
}
请注意,getRGB()
和getName()
两种方法都声明为synchronized
,而set(…)
方法也包含synchronized
块。
现在想象一下这个场景:让我们忘记所有这些synchronized
块,即让我们看看会发生什么,如果他们不在那里。我们有两个线程A和B.
线程A想要执行以下语句:
color.set(0, 0, 0, "Black");
int colorIntA = color.getRGB();
String colorNameA = color.getName();
线程B想要执行相同的操作,但颜色为白色:
color.set(255, 255, 255, "White");
int colorIntB = color.getRGB();
String colorNameB = color.getName();
如果一切顺利,colorIntA
为0,colorNameA
为“黑色”,colorIntB
为16777215,colorNameB为“白色”。
现在假设调度程序决定在执行getRGB()
之后中断执行线程A 但在 getName()
之前执行。同时所有的threadB运行。所以整个执行看起来像这样:
color.set(0, 0, 0, "Black");
int colorIntA = color.getRGB();
// here thread A is interrupted and all of thread B runs
color.set(255, 255, 255, "White");
int colorIntB = color.getRGB();
String colorNameB = color.getName();
// thread B is done, continuing with remaining statement of thread A
String colorNameA = color.getName();
现在colorIntB
和colorNameB
一切顺利,但线程A的变量不一致:colorIntA
为0(如预期的那样),但colorNameA
为“白色”!这是教程谈论的不一致。
使用synchronized
块避免了这种所谓的竞争条件,因为在线程A完成之前不允许线程B与color
一起使用,即线程B必须等到线程A的synchronized
块完全结束。
当您在getRGB()
和getName()
之间放置以下类似内容时,您可能会看到问题在于行动,这会导致0到5秒之间的随机等待:
try {
Thread.sleep((long)(Math.random() * 5000));
} catch (InterruptedException e) {
// not relevant in this case
}