假设我们有一个具有两个同步块的类:
class A{
public synchronized void methodA{
// Do Something
}
public synchronized void methodB{
// Do Something
}
}
假设我们有两个线程t1
和t2
共享同一个类A
的实例。如果t1
将使用A
类的实例调用methodA
,同时t2
将使用t1
使用的A
类的同一个实例调用methodB
。根据我的理解,t2
将被阻止使用同步方法methodB
,即使t1
只使用methodA
。这是因为每个对象都有一个锁,这个锁是由t1
获取的。对吗?如果是,如果我们有两个同步块,我们能得出相同的结论吗?
可以。
:
synchronized void foo() {
code();
}
是
的简写:void foo() {
synchronized (this) {
code();
}
}
由于同样的原因,拥有一个公共字段通常是一个非常糟糕的主意,拥有一个公共锁(this
通常是"公共的",从这个意义上说,来自包外的代码可以访问它)是一个非常糟糕的主意。通常最好这样做:
class Example {
private final Object lock = new Object[0];
public void foo() {
synchronized (lock) {
code();
}
}
}
如果>如果您将锁设置为公共锁(例如,使用synchronized
,或者其他锁在您直接控制之外的代码可以访问),则必须将此记录下来,并非常详细地说明您在未来的更新中承诺使用该锁做什么和不做什么。
没有回答你的问题(rzwitzerloot做得很好,)但是
t2
将被阻止使用同步方法methodB
,即使t1
只使用methodA
。
我们并不需要synchronized
来防止两个线程调用同一个方法。这不是重点。方法是不可变的。两个线程在同一个方法本身中不会产生任何危害。当两个(或多个)线程访问相同的数据时,问题就来了。
如果两个线程在两个不同的对象上调用相同的实例方法,那可能没有问题。如果两个线程在同一个对象上调用两个不同的方法,就是,当我们希望synchronized
防止任何线程看到对象处于无效状态(或者更糟的是,防止任何线程使对象处于无效状态时。
public final class A
{
public synchronized void methodA
{
// Do Something
}
public synchronized void methodB
{
// Do Something
}
}
等价于
public final class A
{
public void methodA
{
synchronized( this )
{
// Do Something
}
}
public void methodB
{
synchronized( this )
{
// Do Something
}
}
}
所以基本上,你的假设是正确的,你可以用两个synchronized
块代替synchronized
方法来达到同样的效果。
synchronize
语句都使用相同的对象作为'参数'!在这种情况下,它是实例本身,因此很容易。
但是我也在一些代码中看到过这种情况:
public final class A
{
/* DO NOT DO THIS */
private static final Object m_LockForA = new Object [0];
private static final Object m_LockForB = new Object [0];
public void methodA
{
synchronized( m_LockForA )
{
// Do Something
}
}
public void methodB
{
synchronized( m_LockForB )
{
// Do Something
}
}
}
这将以某种方式工作(也许它甚至打算以这种方式工作…),但与原始代码完全不同。