如何使用synchronized锁定整个类的方法?

我知道当你想锁定只用一个线程执行的方法时,你用synchronized关键字声明它。

那么类,如何在线程在该类的实例上执行某些代码时对整个对象类进行锁定呢?

换句话说,当一个线程在一个对象上执行一个方法时,即使在同一个类的不同实例上也不应该允许其他线程执行相同的方法。

您可以在特定对象上同步,可以是某个指定的静态锁定对象,也可以是类对象(当声明静态方法被同步时会发生):

 class X { private static final Object lock = new Object(); public void oneAtATime() { synchronized (lock) { // Do stuff } } } class Y { public void oneAtATime() { synchronized (Y.class) { // Do stuff } } } 

每种变体都有自己的优点和缺点; 锁定类允许类之外的其他代码使用相同的锁,原因是它(它允许它协调比你提供的更高级别的同步),而static final Object lock方法允许你禁止它使锁定字段为私有(这使得更容易推断锁定并避免代码死锁,因为其他人编写了错误的代码)。

您当然也可以使用java.util.concurrent一些同步机制,例如显式Lock ,它提供对锁定的更多控制(并且ReentrantLock当前比高争用下的隐式锁执行得更好)。


编辑:请注意,静态/全局锁定不是一个好方法 – 它意味着所创建的类的每个实例都将基本上绑定到每个其他实例(除了使测试或读取代码更加困难之外,它可以严重损害可扩展性)。 我假设你这样做是为了同步某种全局状态? 在这种情况下,我会考虑在类中包装该全局/静态状态,并实现每个实例的同步而不是全局。

而不是像这样的东西:

 class Z { private static int state; public void oneAtATime(){ synchronized (Z.class) { state++; } } } 

像这样做:

 class State { private int value; public synchronized void mutate(){ value++; } } class Z { private final State state; public Z(State state){ this.state = state; } public void oneAtATime(){ state.mutate(); } } // Usage: State s1 = new State(), s2 = new State(); Z foo = new Z(s1); Z bar = new Z(s1); Z frob = new Z(s2); Z quux = new Z(s2); 

现在foobar仍然相互联系,但他们可以独立于frobquux

如果使用静态同步方法,则通过类锁定锁定它们。 你也可以在类中声明一个静态Object,并在一个我相信的方法中将其锁定,例如:

 private static final Object STATIC_LOCK = new Object(); private void foo() { synchronized (STATIC_LOCK) { //do stuff... } } 

您可以在该方法中使用静态Mutex 。 所以任何并发线程都在方法内阻塞,而另一个并发运行它,无论它属于哪个类的对象。 我不认为有任何特殊的单一关键字可以产生像synchronized一样的效果。

这是一个相当激进的同步,我会尽可能地避免它。

在类的静态字段或类本身上同步:

 synchronized(MyClass.class) { // mutually excluded method body } 

两个线程都必须使用这种结构

 public void someMethod() { synchronized(ClassThatShouldBeProtected.class) { someSynchronizedCode(); } } 

这种方法得益于这样一个事实,即类本身就是一个对象,因此它有一个监视器。 那你就不需要任何人工静态实例了。

没有内置机制。 创建自己的静态锁属性,并确保锁定它并在每种方法中解锁它。 不要忘记exception – 确保在“finally”部分解锁。

这应该工作:

 public class MyClass { void synchronizedMethod() { synchronized (MyClass.class) { // synchronized on static level } } } 

哪个’错过’类的锁定运行时表示。 这是可能的,因为任何对象都可以用作Java中的互斥锁。

http://www.janeg.ca/scjp/threads/synchronization.html

谈谈实现它的几种方法。 一般来说,锁是禁止的,并且阻碍了线程的好处。 所以关键代码应该尽可能地最小化。

你想要一个类杠杆锁来访问类的静态变量,还是要保护对类的公共外部资源的访问? 在这种情况下,您应该在访问它时有一个单独的锁。