“同步”背后发生了什么?

时间:2016-03-13 10:45:22

标签: java multithreading 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;
    }
}

3 个答案:

答案 0 :(得分:5)

  

疑问是下面的代码片段将如何制作程序   线程安全的?

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

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

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

  

幕后发生了什么?

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

Java monitor entry set wait set

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

  • 如果没有线程当前拥有监视器且没有其他线程在条目集中等待,则该线程将成为监视器的所有者并开始执行代码。这称为活动线程。
  • 否则,如果有另一个拥有监视器的线程,则当前线程放在Entry set中,并且必须等待Entry Set中其他已存在的线程,如果任何

当前线程在Entry Set

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

注意:如上所述,对于上述讨论,我们假设Wait Set中没有线程以简化讨论。通过Wait Setwait()来电notify()来了解{{1}}。

我建议并且值得一看https://www.artima.com/insidejvm/ed2/threadsynchP.html以获得有关显示器,入门套件和放大器的详细说明。等待。

答案 1 :(得分:1)

如果我们有 Thread1 Thread2 Thread3 ,前两个等待释放,第三个是释放它们的那个,订单会这样。

Thread1 进入并调用wait()
Thread2 进入并调用wait()
Thread3 进入并调用notifyAll()
Thread3 完成,总是

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

答案 2 :(得分:1)

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.   
  3. 评估结果分配给=。
  4. 左侧的变量   

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

Visibility Demonstration