同步使对象锁定

Posted

技术标签:

【中文标题】同步使对象锁定【英文标题】:Synchronized makes object lock 【发布时间】:2010-06-23 18:23:04 【问题描述】:

我对对象锁定感到困惑。 下面的类有 4 个方法,方法 addB() 是同步的。

在我的场景中,有 4 个线程。当线程 2 访问 addB() 方法(它在 Test 对象上创建一个锁)时,是否会有其他线程同时访问 addC() 或 addD()?

对象锁是否一次只允许一个线程?

class Test
       private Integer a;
       private Integer b;
       private Integer c;
       private Integer d;


   public void addA()
      synchronized(a) 
         a++;
      
   
   public synchronized void addB()
         b++;
      

   public void addC()
         c++;
      

   public void addD()
         d++;
          
   

编辑: 我有 3 个线程(t1、t2 和 t3),每个线程都将访问 addB()、addC() 和 addD()。如果线程 t1 访问方法 addB(),线程 t2 可以同时访问 addC() 方法吗?如果不是,t2 状态是什么?

class Test
       private Integer a;
       private Integer b;
       private Integer c;
       private Integer d;


   public void addA()
      synchronized(a) 
         a++;
      
   
   public synchronized void addB()
         b++;
      

   public synchronized void addC()
         c++;
      

   public synchronized void addD()
         d++;
          
   

【问题讨论】:

整数是不可变的,这意味着它永远不会改变。当您执行 a++ 时,它实际上会创建一个新对象 a。因此,您的锁会变得混乱,因为当 a 被删除并将值分配给新的 a 时,锁将丢失。这并不能真正帮助您解决问题,但可能会在以后解决错误。您可以使用 int 代替 Integer。 @Mike - 不错的收获。实际上,我认为在这种特殊情况下它不会导致错误,但如果他将任何代码添加到他的 addA 实现中,则很有可能。此外,他无法在 int 上进行同步,因为它是一个原语,但他可以使用 AtomicInteger @danben 谢谢。我不知道没有在 int 上同步。我想我从未尝试过原始的。你每天都会学到一些东西。 【参考方案1】:

锁确实一次只允许一个线程,但不同的锁不会相互影响。

在您的示例中,您有两个锁 - 一个在属于 a 的互斥锁上,一个在属于 this 的互斥锁上(当您使用 synchronized 关键字时,这是隐含的,正如您在你的帖子)。

因此对addB() 的调用将被同步,但不会阻止对任何其他方法的调用。如果一个线程持有this上的锁,另一个线程可以持有a上的锁,并且多个其他线程可以同时执行addC()addD()

编辑:顺便说一句,如果你真的在使用Integers,你可能有兴趣了解AtomicInteger 类。它们提供原子操作,因此您无需担心围绕它们进行同步。

【讨论】:

我想我们不应该告诉同步创建对象锁,因为其他线程可以在对象锁状态下访问非同步方法。我还是很困惑对象锁是什么意思? @Thomman:我不确定您所说的“处于对象锁定状态”是什么意思。 Java 中的每个对象都有自己的互斥锁 - 当您在对象上进行同步时,在线程可以进入同步块之前需要持有这个互斥锁。【参考方案2】:

同步块只是一个环境,您可以在其中将“执行”它的对象视为reentrant lock。实际上,只允许一个线程同时锁定一个对象。

方法C和D从不加锁,任何线程都可以随时执行。

正如其他所指出的,当您执行 a++ 时,您会创建一个新的 Integer 实例。

【讨论】:

【参考方案3】:

您的代码中有两个锁,只有一个线程能够遍历 Lock #1 或 Lock #2。两个锁都是独立的,这意味着它们不会相互排斥线程。

Lock #1 在对象上同步

   public void addA()
      synchronized(a) 
         a++;
      
   

lock #2 在测试实例上同步(this)

   public synchronized void addB()
         b++;
      

addC() 和 addD() 根本没有锁,任何数量的线程都可以同时访问它们。

【讨论】:

【参考方案4】:

Lock 提供了一种同步线程的机制。这意味着在同一时间点只有一个线程可以访问对象的 AddB 方法。 除非在代码完成后释放锁,否则下一次代码迭代无法进入块。

【讨论】:

【参考方案5】:

线程的锁定取决于所用对象的实例 例如:

class MyClass extends Thread
   Test instanceObj=null;    
   public MyClass(Test obj)
      instanceObj=obj;
   

   public void run()
      obj.addB();
   

addB()函数可以改写为

public void addB()
  synchronized(this)
    //func
 

这里的锁是对象上的,用于访问函数的 sn-p。 其他函数可以被其他线程访问。 addA 上的锁更多是在一个对象 obj.a 上,它有自己的独立锁。因此两个不同的线程可以同时访问 addA 和 addB。

【讨论】:

以上是关于同步使对象锁定的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程---同步与锁

销毁全局对象[关闭]

java同步中,为啥要wait,又notify谁?

多线程

对象级别锁 vs 类级别锁 – Java

python-锁机制