【问题标题】:Clarification on the meaning of the parameter block synchronization澄清参数块同步的含义
【发布时间】:2013-10-09 20:26:14
【问题描述】:

我想知道这个表达式是否正确以及它是否意味着:我在字段状态上放置了一个写锁,然后我改变了它。如果没有,我想知道参数的含义是什么,因为我总是看到 this

public class Example {
    private int status;
    public Example(int status){
        this.status = status;
    }
    public void setStatus(int newStatus){
        synchronized(this.status){
            this.status = newStatus;
        }
     }
}

【问题讨论】:

    标签: java synchronized


    【解决方案1】:

    这段代码有几个问题:

    1. 您不能在原语上synchronize

      您可以将其更改为 Integer,但请参见下文。

    2. 在非最终对象上同步不是一个好主意。

      你可以做到final

    3. synchronized 打开时更改字段会以一些非常模糊的方式中断。现在是final 不允许。

      在另一个字段上同步可能更好。

    4. 您还应该提供一个 get 方法以确保完整性。

    解决所有这些问题后,您的代码如下所示:

    public class Example {
      private final Object statusLock = new Object();
      private Integer status;
    
      public Example(Integer status) {
        this.status = status;
      }
    
      public void setStatus(Integer newStatus) {
        synchronized (statusLock) {
          status = newStatus;
        }
      }
    
    
      public Integer getStatus() {
        return status;
      }
    }
    

    现在 - 使用此代码 - 您的问题的答案是 。这里发生的情况是,当您更改它的值时,您从任何其他线程锁定所有status 字段通过 set 方法的访问。

    请注意,我没有在 get 方法中进行同步。如果我这样做了,那么上面的陈述就会改变。

    【讨论】:

    • 我在示例中使用了原语,但在我的项目中我使用了对象
    • @Oxenarf - 您仍然无法更改您在 setter 中锁定的对象。
    【解决方案2】:

    不,你的表达并不代表你的想法。同步块的参数是你在运行同步块之前获得的锁,并在最后释放。在 Java 中,继承自 Object 的所有东西都可以用作锁(所以不,int 不能用作锁)。

    一个锁一次只能被一个线程持有,但是如果给定不同的对象作为参数,同一个同步块中的代码可以同时在多个线程中运行。另一方面,如果两个不同的同步块被赋予相同的锁作为参数,两个线程将无法从不同的同步块运行不同的代码。

    人们经常使用this 作为锁,但也经常使用专门用作锁的对象,这就是 OldCurmudgeon 在她的回答中所做的。

    【讨论】:

      【解决方案3】:

      我看到您正在同步字段this.status,它是int。 在原始类型上同步是不可能的。仅在对象或类上。

      为什么不考虑使用AtomicInteger

          public class Example
      {
        private AtomicInteger status;
      
        public Example(int status)
        {
          this.status = new AtomicInteger(status);
        }
      
        public void setStatus(int newStatus)
        {
          this.status.getAndSet(newStatus);
        }
      }
      

      【讨论】:

      • 正确,但应该是评论,因为它没有回答 OP 的问题。
      猜你喜欢
      • 2019-06-14
      • 1970-01-01
      • 1970-01-01
      • 2016-04-08
      • 1970-01-01
      • 2014-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多