【问题标题】:How does the synchronize functionality work in java?java中的同步功能是如何工作的?
【发布时间】:2011-07-05 14:31:18
【问题描述】:

自从我开始使用 Java 编程以来,我一直想知道这一点(大约一两年)。在C语言中,我们必须知道正确避免线程之间死锁的不同方法,因此在同步方法之间有更多的选择。

那么 Java 呢?当我们同步时,它如何避免使线程陷入死锁情况?它在内部是如何工作的?是否因为我们在比 C(或 C++)更高的级别上同步而避免了死锁?有没有关于 java 中的死锁和同步的文档?

【问题讨论】:

    标签: java synchronization deadlock


    【解决方案1】:

    在底层,它在字节码级别使用两个操作码 monitorentermonitorexit,它们在 JVM 全局级别获取/释放对象引用上的锁。我强烈推荐你阅读How the Java virtual machine performs thread synchronization

    【讨论】:

      【解决方案2】:

      我们在多线程代码中遇到的主要问题是共享数据,我同意并发并行化进程的目的,并且它“经常”发生在并行化处理期间,线程需要访问以在共享上进行读/写数据。

      java synchronized 关键字允许以下内容:

      它告诉 JVM 对对象或同步代码段的监视器加锁,这使其能够独占访问该部分代码或对象。

      这是一个单例的例子:

      public class Singleton {
          private Singleton INSTANCE;
      
          private Singleton() {
          }
      
          public Singleton getInstance() {
              if (null == INSTANCE) {
                  INSTANCE = new Singleton();
              }
              return INSTANCE;
          }
      }
      

      这个 Singleton 不是线程安全的,如果一个线程试图获取一个实例,而另一个线程也在尝试做同样的事情(竞争条件),那么在第一个线程完成之前可能会发生第二个实例的创建已经可以访问getInstance() 方法并创建了他自己的Singleton 实例,这意味着在T 时间我们应该有两个Singleton 实例(当时称为multiton)。

      为了解决这个问题,我们必须同步单例的创建行为,这可以通过INSTANCE本身的if语句上方的关键字synchronized来完成:

      public class Singleton {
          private Singleton INSTANCE;
      
          private Singleton() {
          }
      
          public Singleton getInstance() {
              synchronized (Singleton.class) {
                  if (null == INSTANCE) {
                      synchronized(Singleton.class) {
                         Singleton inst = new Singleton();
                         INSTANCE = inst;   
                      }
                  }
              }
              return INSTANCE;
          }
      }
      

      结果是当第一个线程询问 Singleton 实例时,在创建期间,JVM 将锁定实例的监视器,拒绝对实例的任何访问,直到线程完成其请求。

      也有不同的方法来实现这一点,之前引用的书是一个很好的学习资源,javadoc 也是。

      【讨论】:

        【解决方案3】:

        Java 中的同步实际上并没有 C 中那么容易。在语法上更容易,因为您需要为互斥锁做的就是将方法声明为同步或使用

        synchronized(someObject)
        {
           someCode();
        }
        

        而在 C/C++ 中,您必须使用特定于操作系统的函数才能使用互斥锁,或者您必须使用 Boost 库。

        但是关于死锁的陷阱基本上和任何语言都是一样的。

        【讨论】:

        • 谢谢!但是synchronized关键字究竟是什么,它是一个互斥体?而在不同的平台上,由于线程可以不同,它也会不同吗?
        • 它是一个互斥体。一个可重入互斥体。
        【解决方案4】:

        简短回答:

        1. synchronized 方法和 lock 块使用 监视器 在方法或块的持续时间内锁定锁定对象的 信号量

        2. Java 语言本身并不能防止死锁。作为程序员,这取决于您确保对象以正确的顺序锁定/解锁以防止争用。

        【讨论】:

          【解决方案5】:

          您还必须注意 Java 中的死锁。获得死锁的最简单方法是让一个线程在 A 上运行一个同步块,然后在 B 上同步另一个块,而另一个线程在 B 上执行一个同步块,然后在 A 上同步一个块。

          阅读the Java tutorial about concurrency.,如果你想继续学习,阅读Java concurrency in practice

          【讨论】:

            【解决方案6】:

            你试过google (Java Deadlock)吗?第一个结果是这样的:http://download.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

            在那里您可以看到synchronized 仍然会发生死锁,因为同步并不是一开始就旨在防止这些死锁。

            【讨论】:

            • 嗯,我的问题不仅仅是关于僵局。我知道什么是死锁,并且我知道大多数众所周知的问题(哲学家晚宴等)。它也与 synchronized 关键字的内部功能有关。我想知道更多关于它是如何工作的细节。
            • @Zonata 那么您是否看过有关同步的 Oracle 文档?这只是我链接的死锁部分之前的一章。回复主要针对这个问题:When we synchronize, how does it avoid putting thread in deadlock situation? - 它没有。
            【解决方案7】:

            我看到上面的 Singleton 存在一些问题。我认为永远不会创建该类。请考虑下面的代码。

            public class Singleton {
                 private static Singleton INSTANCE;
                 private Singleton() {     }
                 public static Singleton getInstance() {
                     synchronized (Singleton.class) {
                         if (null == INSTANCE) {
                             synchronized(Singleton.class) {
                                Singleton inst = new Singleton();
                                INSTANCE = inst;
                                }
                         }
                     }
                     return INSTANCE;
                 }
             } 
            

            【讨论】:

            • 为什么永远不会创建这个类?
            猜你喜欢
            • 2010-10-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-07-04
            • 1970-01-01
            • 2017-07-12
            相关资源
            最近更新 更多