首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是进入同步块原子吗?

是进入同步块原子吗?
EN

Stack Overflow用户
提问于 2015-03-23 18:03:43
回答 3查看 1.6K关注 0票数 4

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

想象下面的情况

Thread_1,2:

代码语言:javascript
复制
synchronized(object){object.modify();}

(对象是共享变量。)

假设thread_M会更改对对象的引用,如

代码语言:javascript
复制
synchronized(object){object = new Object()}

现在假设线程1和2正在争夺对象上的锁。

是否有可能发生以下情况:

  1. Thread1:读取旧对象
  2. ThreadM:修改对象引用并释放旧的对象锁
  3. Thread2:读取新对象;检查锁;锁定它
  4. Thread1:检查锁(好的,因为读取了旧对象);锁定它 现在,两个线程都有一个锁,并修改了同一个(新的)对象。

因此,为了明确我的问题--是否保证在同步(对象)步骤(1和4)中原子化(如步骤3所示)?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-03-23 18:24:51

您可以在object上同步时重新分配object,但我想不出重新分配用于锁定的字段是个好主意。

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

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

object声明为volatile变量将确保其“当前”值用于锁定。但是它不会阻止两个线程并发地修改同一个实例:

  1. 线程M获取旧值的锁定。线程1读取旧值。
  2. 线程M更改该值。
  3. 线程M释放对旧值的锁定。线程2读取新值。
  4. 线程1获取旧值的锁定。线程2获取新值的锁定。
  5. 线程1读取新值。线程2读取新值。
  6. 线程1修改新值。线程2修改新值。

为了避免这一切,只需创建一个单独的对象进行锁定,并且永远不要更改它。

票数 1
EN

Stack Overflow用户

发布于 2015-03-23 18:56:16

假设您有一些变量,foo

代码语言:javascript
复制
Foo foo;

并且假设它持有对一个对象的引用:

代码语言:javascript
复制
foo = new Foo(...);

假设我们有一个synchronized块:

代码语言:javascript
复制
synchronized(foo) {
    ...
}

synchronized keywoord不对变量foo进行操作,也不对同步块中的语句进行操作。

synchronized关键字在这里所做的唯一的事情就是防止其他线程同时在同一个实例上同步。

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

票数 2
EN

Stack Overflow用户

发布于 2015-03-23 18:09:34

您正在对" object“指向的对象进行同步,而不是对持有该值的变量进行同步。

然而,因为这两段代码都在您的对象上同步,所以您是安全的--尽管这是一个糟糕的设计模式。

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

而且,这只是我的观点,但是同步(对象)似乎是一个非常糟糕的设计模式。这只是我的意见,但我从来没做过这样的事。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29217266

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档