Лучшая практика заключается в использовании частного держателя замка. Это предотвращает блокировку вашего кода вне класса. Это показано в приведенном ниже примере. Обратите внимание на порядок выполнения на выходе - DoMathExposed # getSum() не может вернуться до выхода общедоступного класса монитора. С другой стороны, DoMathEncapsulated # getSum() возвращается сразу же после синхронизации на частном объекте, поэтому сохранение монитора общественного класса не имеет никакого эффекта.
import java.util.concurrent.CountDownLatch;
public class DoMath {
public static void main(String[] args) throws InterruptedException {
System.out.println("\nTesting DoMathExposed.class\n");
DoMathExposed.x = 3;
DoMathExposed.y = 4;
obtainMonitorOf(DoMathExposed.class);
System.out.println("Invoked DoMathExposed#getSum()");
System.out.println("DoMathExposed#getSum() returned: " + DoMathExposed.getSum());
System.out.println("\nTesting DoMathEncapsulated.class\n");
DoMathEncapsulated.x = 1;
DoMathEncapsulated.y = 2;
obtainMonitorOf(DoMathEncapsulated.class);
System.out.println("Invoked DoMathEncapsulated#getSum()");
System.out.println("DoMathEncapsulated#getSum() returned: " + DoMathEncapsulated.getSum());
}
private static void obtainMonitorOf(final Class cls) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
new Thread(new Runnable() {
@Override
public void run() {
synchronized(cls) {
System.out.println(cls.getName() + ".class MONITOR held for 10 seconds");
latch.countDown();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
}
System.out.println(cls.getName() + ".class MONITOR released");
}
}).start();
latch.await();
}
}
class DoMathEncapsulated {
private static final Object lock = new Object();
protected static int x;
protected static int y;
public static int getSum() {
synchronized(lock) {
return x + y;
}
}
public int getSub() {
synchronized(lock) {
return x - y;
}
}
}
class DoMathExposed {
protected static int x;
protected static int y;
public static synchronized int getSum() {
return x + y;
}
public int getSub() {
synchronized(DoMathExposed.class) {
return x - y;
}
}
}
Но можем ли мы сделать блокировку на уровне экземпляра методом экземпляра? –
Да. И это то, что делает моя реализация 'getSub'. –