【问题标题】:What is happening behind "Synchronized"? [duplicate]“同步”背后发生了什么? [复制]
【发布时间】:2016-06-28 09:53:33
【问题描述】:

我知道要使程序线程安全,建议使用synchronized 方法或代码块。疑问是下面的代码 sn-p 将如何使程序线程安全?幕后发生了什么?

public class MyCounter
{
    private int count = 0; // count starts at zero

    public synchronized void setCount(int amount)
    { 
        count = amount;
    }

    public synchronized int getCount()
    {
        return count;
    }
}

【问题讨论】:

  • 使代码线程安全并不是一个简单的“同步”问题。即使是了解基础知识也需要教程,这对于本网站来说太长了。

标签: java multithreading synchronized


【解决方案1】:

疑问是下面的代码 sn -p 将如何制作程序 线程安全?

这里的关键是 每个 java 对象都有一个与之关联的隐式监视器,并且在任何时间点只有一个线程可以进入对象监视器,其他试图进入此监视器的线程将排队进入设置或等待设置。

当一个线程试图执行一个标记为synchronized的方法时,它应该在执行该方法中的代码之前获得implicit monitor的所有权。

在您的情况下,您有两种方法,都标记为synchronized。由于使用synchronized 关键字,只有一个线程能够获取执行这些方法中的任何一个所需的对象监视器,因此在任何时候只有一个线程可以执行这些synchronized 方法,因此它们是线程安全的。

幕后发生了什么?

要了解对象监视器、所有权、等待集和条目集如何协同工作,让我们看下面的图片,它表示每个 java 对象唯一的 implicit monitor。如我们所见,有两个入口点来获取监视器,即从Entry Set 或从Wait Set。对于我们的讨论,我们将仅从Entry Set 的角度进行流程,并假设Wait Set 为空。

当线程调用synchronized 方法时,它被放置在Entry Set 中。

  • 如果当前没有线程拥有监视器并且没有其他线程在条目集中等待,则线程将成为监视器的所有者并开始执行代码。这称为活动线程。
  • 否则,如果有另一个线程拥有监视器,则当前线程将被放置在 Entry set 中,并且必须与 Entry Set 中的其他现有线程(如果有)一起等待轮到它。李>

当当前线程在Entry Set中等待时,

  • 活动线程将在执行完同步块中的代码后释放监视器。 (其他发布方式是通过wait() 方法,我们将在讨论中忽略)
  • 随后,由于监视器现在空闲,条目集中的线程将竞争获取监视器,其中一个将获得机会。

注意:如上所述,对于上述讨论,我们假设Wait Set 中没有线程,以保持讨论的重点。 Wait Setwait()notify() 通话一起出现在图片中。

我建议并且值得一看 https://www.artima.com/insidejvm/ed2/threadsynchP.html 以获取有关监视器、入口集和等待集的更详细说明。

【讨论】:

  • 坦率地说,它提供了很多清晰度。;)
【解决方案2】:

如果我们有 Thread1Thread2Thread3,其中前两个等待释放,第三个等待释放它们,顺序会这样。

Thread1 进入并调用wait()
Thread2 进入并调用wait()
Thread3 进入并调用@987654323 @
Thread3 总是结束

然而,等待的线程没有特定的顺序。
哪个先执行,完全是随机的,与他们调用wait() 的顺序无关。然而,调用notify(All) 的线程将始终在任何等待线程继续之前完成。

【讨论】:

    【解决方案3】:
    public synchronized void setCount(int amount)
    { 
            count = amount;  <-- *this operation is not atomic, and hence multiple thread execution may interleave resulting in race conditions*
    }
    

    执行赋值运算符时有两个步骤:

    1. 计算 = 右侧的表达式。
    2. 求值结果赋值给=左边的变量。

    注意:getter 和 setter 需要与同一个监视器同步,因为它也解决了visibility 的问题。如果没有同步,如果一个线程调用 setter,另一个线程调用 setter,则不能保证第二个线程会看到更新的值。

    Visibility Demonstration

    【讨论】:

      猜你喜欢
      • 2019-08-23
      • 1970-01-01
      • 2014-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多