Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 进入同步块是原子的吗?_Java_Multithreading_Synchronization_Synchronized - Fatal编程技术网

Java 进入同步块是原子的吗?

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:检

您知道java中的同步块是否保证是原子的吗

想象一下下面的情况

螺纹1,2:

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)允许您使用较小的块进行同步。不,我是在问是否可以更改对正在同步的对象的引用(前提是更改本身在同步化块中)