プライベートロックホルダーを使用することをお勧めします。これにより、クラスの外側からコードをロックすることを防ぎます。これは以下の例で実証されています。パブリックにアクセス可能なクラスモニターが解放される前に、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'の実装がやっていることです。 –