2 つのスレッドが同期ブロックに同時にアクセスするにはどうすればよいですか? つまり、このスレッドが同じ同期ブロックの実行を終了する前であっても、あるスレッドが他のスレッドに同期ブロックを実行する機会を与えるにはどうすればよいでしょうか?
5 に答える
wait()、notify()、およびnotifyAll()を参照してください。
編集:あなたの質問への編集は正しくありません。sleep() メソッドはモニターを解放しません。
例えば:
private static final Object lock = new Object();
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.execute(new One());
executorService.execute(new Two());
}
static class One implements Runnable {
@Override
public void run() {
synchronized (lock) {
System.out.println("(One) I own the lock");
System.out.println("(One) Giving up the lock and waiting");
try {
lock.wait();
} catch (InterruptedException e) {
System.err.println("(One) I shouldn't have been interrupted");
}
System.out.println("(One) I have the lock back now");
}
}
}
static class Two implements Runnable {
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.err.println("(Two) I shouldn't have been interrupted");
}
synchronized (lock) {
System.out.println("(Two) Now I own the lock (Two)");
System.out.println("(Two) Giving up the lock using notify()");
lock.notify();
}
}
}
複数の同期ブロックの使用を検討する必要があるように思えます。特に、1 つのスレッドがキャッチされているブロック操作があり、ブロック内で別の何かを実行しようとしている別のスレッドをブロックしている場合はそうです。
同期ブロックは、(定義により) 一度に 1 つのスレッドのみがアクセスできるコードのブロックです。別のスレッドが現在このブロックを処理している間に別のスレッドがこのブロックに入るようにすると、同期ブロック スキームは役に立たなくなります。
おそらく、同期ブロックを他の多くのブロックに分割したいと思うでしょう。
スレッドは、 を使用してモニターを解放できますlock.wait()
。その後、別のスレッドがモニターを取得して、同期ブロックに入ることができます。
例:
public class MultipleThreadsInSynchronizedBlock {
public static void main(String... args) {
final Object lock = new Object();
Runnable runnable = new Runnable() {
public void run() {
synchronized (lock) {
System.out.println("Before wait");
try {
lock.wait();
} catch (InterruptedException e) {
}
System.out.println("After wait");
}
}
};
new Thread(runnable).start();
new Thread(runnable).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
synchronized (lock) {
lock.notifyAll();
}
}
}
これは以下を出力します:
Before wait
Before wait
After wait
After wait
ただし、相互に排他的なブロックを非アトミックに実行できるようにすることは「ハック」ではありません。このような非常に低レベルの同期プリミティブを使用する場合は、何をしているのかを知る必要があります。
wait()
1 つのスレッドがモニター オブジェクトを呼び出しているかどうかを確認できる唯一の方法です。次に、モニターを解放し、他のスレッドが同期ブロックを実行できる間、通知を待ちます。次に、他のスレッドが呼び出す必要がnotify()/notifyAll()
あるため、最初のスレッドがモニターを取得して続行します。