你知道是否可以保证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所示)?
答案 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用于锁定。但它不会阻止两个线程同时修改同一个实例:
要避免所有这些,只需创建一个单独的对象进行锁定,而不要更改它。
答案 2 :(得分:0)
您正在同步“对象”所指向的对象,而不是保存该值的变量。
但是,由于这两段代码在向前移动之前会在您的对象上同步,因此您是安全的 - 尽管这是一种糟糕的设计模式。
如果您使用同步方法而不是同步代码块,您可能会发现更少的混淆。
另外,仅仅是我的意见,但同步(对象)似乎是一个非常糟糕的设计模式。这只是我的意见,但我从来没有这样做过。