【问题标题】:How synchronization block works?同步块如何工作?
【发布时间】:2014-03-27 18:45:50
【问题描述】:

错误代码

public class Scheduler {
 private Object lock = new Object();

 private int interval;
 private int period;

 public Scheduler(int interval , int period) {
   this.interval = interval;
   this.period = period;
 }

 public synchronized void  setInterval(int interval) {
     this.interval = interval;
 }

 public synchronized void setPeriod(int period) {
       this.period = period;
 }

 public void updateScheduler(int interval , int period) {
    synchronized(lock) {
      setPeriod(period);
      setInterval(interval);
    }
 }

}

我的代码中有一些线程安全问题来查找这些问题,我在我的项目中运行了线程安全的 Eclipse 插件。

线程安全报告

  1. Scheduler 类中的混合同步

    错误描述

    为避免数据争用,重要的是并发访问的字段始终由公共锁保护。如果每次访问字段时都没有持有相同的锁对象,则可能发生数据竞争。

固定代码

public class Scheduler {
     private Object lock = new Object();

     private int interval;
     private int period;

     public Scheduler(int interval , int period) {
       this.interval = interval;
       this.period = period;
     }

     public void  setInterval(int interval) {
         synchronized(lock) {
            this.interval = interval;
         }
     }

     public void setPeriod(int period) {
          synchronized(lock) {
             this.period = period;
          }
     }

     public void updateScheduler(int interval , int period) {
        synchronized(lock) {
          setPeriod(period);
          setInterval(interval);
        }
     }

    }

我测试了这段代码,它工作正常。我的问题是,我正在从 updateScheduler 内部调用 setPeriodsetInteval。当调用 updateScheduler 时,对象 lock 已经被锁定,然后我正在调用 setIntervalupdateScheduler >锁没有被释放。我期望代码最终会陷入死锁。但是,为什么没有发生呢?

【问题讨论】:

    标签: java multithreading synchronization


    【解决方案1】:

    固定代码 (lock) 中只有一个监视器被锁定,因此不可能出现死锁。

    要修复原始代码,您还可以同步 updateScheduler 方法,而不是使用 lock 对象。它会达到同样的效果。

    就您的问题而言,Java 锁定是“reentrant”,这意味着,当“锁定”的一段代码尝试再次“锁定”它(即使用相同的监视器)时,它理解它的同一个监视器,因此不会阻止/等待它被解锁。它知道它已经“拥有”它。有意义吗?

    【讨论】:

      【解决方案2】:

      Java Language Specification

      一个线程可能会多次锁定一个特定的监视器;每次解锁都会反转一次锁定操作的效果。

      因此您可以为同一个对象嵌套synchronized 块。

      synchronized(lock) {
          synchronized(lock) {
              synchronized(lock) {
                  // ad nauseam and within method calls
              }
          }
      }
      

      这在Intrisic Locks and Synchronization的Java教程中有进一步的解释

      回想一下,一个线程无法获得另一个线程拥有的锁。 但是线程可以获取它已经拥有的锁。 允许线程多次获取同一个锁可以实现重入 同步。这描述了同步代码的情况, 直接或间接调用一个方法,该方法还包含 同步代码,并且两组代码使用相同的锁。没有 可重入同步,同步代码要花很多时间 避免线程导致自身阻塞的额外预防措施。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-04
        • 2019-08-31
        • 1970-01-01
        • 1970-01-01
        • 2011-10-27
        • 2015-04-12
        • 1970-01-01
        • 2010-11-03
        相关资源
        最近更新 更多