同步使对象锁定
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()
。
编辑:顺便说一句,如果你真的在使用Integer
s,你可能有兴趣了解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。
【讨论】:
以上是关于同步使对象锁定的主要内容,如果未能解决你的问题,请参考以下文章