进入同步块原子?

时间:2015-03-23 18:03:43

标签: java multithreading synchronization synchronized

你知道是否可以保证java中的synchronized块是原子的吗?

想象一下以下案例

Thread_1,2:

synchronized(object){object.modify();}

(对象是共享变量。)

想象thread_M会改变对象的引用,如

synchronized(object){object = new Object()}

现在想象线程1和2争夺对象的锁定

是否有可能发生以下情况:
1. Thread1:读取旧对象
2. ThreadM:修改对象引用&释放旧物体锁
3. Thread2:读取新对象;检查锁;锁上它 4. Thread1:检查锁定(ok cos旧对象被读取);锁上它 现在两个线程都有一个锁并修改相同的(新)对象

所以要指定我的问题 - 在某个地方保证在同步(对象)步骤(1和4)中是原子的(如步骤3所示)?

3 个答案:

答案 0 :(得分:2)

假设您有一些变量foo

Foo foo;

并假设它包含对象的引用:

foo = new Foo(...);

假设我们有synchronized块:

synchronized(foo) {
    ...
}

synchronized关键字对变量foo进行操作,并且对同步块中的语句进行操作。

synchronized关键字唯一能做的就是阻止其他线程同时在同一个实例上进行同步。

如果重新分配变量foo以引用一些不同的实例,而线程A在块内,那么其他一些线程B将能够同时进入同一个块,因为这两个中的每一个都是线程将在不同的实例上同步。

答案 1 :(得分:1)

您在<{1}}上同步时可以重新分配object,但我无法想到重新分配用于锁定的字段的情况想法。

在线程M退出其同步块之前,没有其他线程能够获取object旧值的锁定,但是另一个线程将能够立即获取新对象的锁定对该线程可见。

在释放锁之前由线程进行的修改保证对之后获取锁的线程可见。但是,由于您正在重新分配锁本身,因此获取线程可能看不到它已被更改,并获取旧值的锁定。然后他们仍然不会看到object已被重新分配。

object声明为object变量可确保其{&#34;当前&#34; value用于锁定。但它不会阻止两个线程同时修改同一个实例:

  1. 线程M获取对旧值的锁定。线程1读取旧值。
  2. 线程M更改值。
  3. 线程M释放对旧值的锁定。线程2读取新值。
  4. 线程1获取旧值的锁定。线程2获取新值的锁定。
  5. 线程1读取新值。线程2读取新值。
  6. 线程1修改新值。线程2修改新值。
  7. 要避免所有这些,只需创建一个单独的对象进行锁定,而不要更改它。

答案 2 :(得分:0)

您正在同步“对象”所指向的对象,而不是保存该值的变量。

但是,由于这两段代码在向前移动之前会在您的对象上同步,因此您是安全的 - 尽管这是一种糟糕的设计模式。

如果您使用同步方法而不是同步代码块,您可能会发现更少的混淆。

另外,仅仅是我的意见,但同步(对象)似乎是一个非常糟糕的设计模式。这只是我的意见,但我从来没有这样做过。