Java 进入同步块是原子的吗?
您知道java中的同步块是否保证是原子的吗 想象一下下面的情况 螺纹1,2:Java 进入同步块是原子的吗?,java,multithreading,synchronization,synchronized,Java,Multithreading,Synchronization,Synchronized,您知道java中的同步块是否保证是原子的吗 想象一下下面的情况 螺纹1,2: synchronized(object){object.modify();} (对象是共享变量。) 想象一下,线程M将更改对对象的引用,如 synchronized(object){object = new Object()} 现在想象线程1和线程2正在争夺对象的锁 是否可能发生以下情况: 1.线程1:读取旧对象 2.ThreadM:修改对象引用并释放旧对象锁 3.线程2:读取新对象;检查锁;锁定它 4.线程1:检
synchronized(object){object.modify();}
(对象是共享变量。)
想象一下,线程M将更改对对象的引用,如
synchronized(object){object = new Object()}
现在想象线程1和线程2正在争夺对象的锁
是否可能发生以下情况:1.线程1:读取旧对象
2.ThreadM:修改对象引用并释放旧对象锁
3.线程2:读取新对象;检查锁;锁定它
4.线程1:检查锁(正常,因为旧对象已读取);锁定它
现在两个线程都有一个锁并修改相同的(新)对象
因此,要具体说明我的问题-是否在某个地方保证在同步的(对象)步骤(1和4)中是原子的(如步骤3所示)?您是在“对象”指向的对象上进行同步,而不是在保存值的变量上进行同步 然而,因为这两段代码在向前移动之前都在对象上同步,所以您是安全的——尽管这是一种糟糕的设计模式 如果使用同步方法而不是同步代码块,您可能会发现混淆更少 另外,这只是我的观点,但同步(对象)似乎是一种非常糟糕的设计模式。这只是我的观点,但我从来没有做过类似的事情。当您在
对象上进行同步时,您可以重新分配对象
,但我想不出重新分配用于锁定的字段是一个好主意的场景
在线程M退出其同步块之前,没有其他线程能够获取对对象的旧值的锁,但是一旦该线程看到新对象,另一个线程将能够获取该对象的锁
在释放锁之前线程所做的修改保证对随后获取锁的线程可见。但是,由于您正在重新分配锁本身,获取线程可能看不到它已被更改,并获取旧值上的锁。然后他们仍然看不到对象
已被重新分配
将对象
声明为volatile
变量将确保其“当前”值用于锁定。但这不会阻止两个线程同时修改同一个实例:
线程M获得对旧值的锁定。线程1读取旧值李>
线程M更改该值
线程M释放对旧值的锁定。线程2读取新值
线程1获得对旧值的锁定。线程2获得对新值的锁定
线程1读取新值。线程2读取新值
线程1修改新值。线程2修改新值
为了避免所有这些,只需创建一个单独的对象进行锁定,并且永远不要更改它。假设您有一些变量,foo
:
Foo foo;
假设它包含对一个对象的引用:
foo = new Foo(...);
假设我们有一个synchronized
块:
synchronized(foo) {
...
}
synchronized
keywoord不操作变量foo
,也不操作synchronized块中的语句
这里,synchronized
关键字所做的唯一一件事是防止其他线程同时在同一实例上同步
如果在线程A位于块内时重新分配变量,foo
以引用某个不同的实例,那么其他一些线程B将能够同时进入同一块,因为两个线程中的每个线程都将在不同的实例上同步。同步的块不是原子的!但它们通过提供适当的锁定机制来帮助防止竞争状况。@jsn你说它们不是原子的是什么意思?在同一对象的同步块上运行的两个线程将以原子方式相互执行。@JohnVint在同步块的语句之间可能会安排另一个线程,因此这不是一个无法打印的所有成功或失败操作。@jsn:我知道其他线程可能会运行。当然,我的问题只与同步的“对象”有关。如果对象是最终的,则2个同步块显然不能进入同步(对象)。关于线程1,2,它将是相互“原子的”(我更愿意说不是交错的)。但问题是,如果线程可以更改对象引用本身(尽管在同步块中),那么锁定过程是否安全。@JohnVint:“同一对象的同步块”是什么意思?块(即代码)不属于对象,块属于类。OP想知道两个线程如何同时进入同一个同步块。答案是,当它们在不同的对象上同步时,它们就可以做到这一点。在上面的例子中,这是无意中发生的,因为程序员认为synchronized(object){…}
对变量进行操作,当它真的在输入块的瞬间对变量引用的对象进行操作时。是的,但我不更改对象所持有的值-请参见我的示例中的thread_M更改对象本身。这可能会造成问题,他不安全。线程1和线程2都可以修改新对象,正如他所怀疑的,因为它们被锁定在两个不同的实例上。我不确定您真正想要实现什么。您可以在对象上同步,而不是在对象的句柄上同步。如果有两个同步块用于同一个对象,那么它们是同步的,但是您所做的是非常可怕的。说真的,同步方法会更安全,也更容易理解。synchronized(object)
1)允许您在其他对象上同步,而不是此
和2)允许您使用较小的块进行同步。不,我是在问是否可以更改对正在同步的对象的引用(前提是更改本身在同步化块中)