"Synchronized" 背后发生了什么?

What is happening behind "Synchronized"?

我了解到要使程序线程安全,建议使用synchronized方法或代码块。疑问是下面的代码片段如何使程序线程安全?幕后发生了什么?

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;
    }
}

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

Thread1进入并调用wait()
线程2进入并调用wait()
线程3进入并调用notifyAll()
Thread3 完成,总是

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

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

Two steps take place when an assignment operator is executed:

  1. The expression on the right of the = is evaluated.
  2. The result of evaluation is assigned to the variable on the left of the =.

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

Visibility Demonstration

The doubt is how the below code snippet will make the program thread-safe?

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

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

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

What is happening behind the scenes?

要了解对象监视器、所有权、等待集和入口集如何协同工作,让我们看下面的图片,它表示每个 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 以获取有关监视器、入口集和等待集的更详细说明。