Java - 再入モニタ
こんにちは、将来のJava魔法使いの皆さん!今日は、Javaの再入モニタの世界に興味深く飛び込んでみましょう。プログラミングが初めての方でも心配しないでください。私はあなたの親切なガイドとして、ステップバイステップで進めていきます。では、 virtual wand(キーボード)を手に取り、一緒に潜りましょう!
再入モニタとは?
本題に入る前に、まず再入モニタとは何かを理解しましょう。あなたが魔法の図書館にいるとします。その図書館には、一度に一人しか入ることができない特定のセクションがあります。それで、あなたがそのセクションにいるのに、さらにサブセクションに進む必要があるとしたらどうでしょうか?再入モニタは、そのセクションに再び入ることができる魔法のパスみたいなものです!
Javaの言葉では、再入モニタはすでにロックを保持しているスレッドが、ブロックすることなくそのロックを再び取得することができるものです。まるで自分がすでにいる部屋に再び入る許可を与えるようなものです。素晴らしいでしょう?
なぜ再入モニタが必要か?
「この魔法のパスが必要なのはなぜだろう?」と疑問に思うかもしれません。マルチスレッドの世界では(複数のプログラム部分が同時に実行される世界)、共有リソースを保護する必要があります。再入モニタは、特にメソッドが他のメソッドを呼び出し、同じロックが必要な場合に、より効率的にこれを行う帮助我们します。
ReentrantLockの紹介
Javaは、再入モニタを実装するためのReentrantLock
というクラスを提供しています。まるで魔法の図書館パス、ただしコード形式のものです!
シntax
以下にReentrantLockの作成と使用方法を示します:
import java.util.concurrent.locks.ReentrantLock;
ReentrantLock lock = new ReentrantLock();
// ロックを取得
lock.lock();
try {
//保護されたコードをここに
} finally {
//ロックを解放
lock.unlock();
}
これが少し威圧的な感じがするかもしれませんが、例を用いて説明します!
再入ロックなしのマルチスレッド
まずはReentrantLockを使用しない簡単な例を見てみましょう。複数の魔法使い(スレッド)がインクリメントを試みる魔法のカウンタを思い浮かべてください:
public class MagicalCounter {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
それで、このカウンタをインクリメントするための魔法使いスレッドを作成します:
public class WizardThread extends Thread {
private MagicalCounter counter;
public WizardThread(MagicalCounter counter) {
this.counter = counter;
}
public void run() {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
}
}
public class MagicalCounterTest {
public static void main(String[] args) throws InterruptedException {
MagicalCounter counter = new MagicalCounter();
WizardThread wizard1 = new WizardThread(counter);
WizardThread wizard2 = new WizardThread(counter);
wizard1.start();
wizard2.start();
wizard1.join();
wizard2.join();
System.out.println("最終カウント: " + counter.getCount());
}
}
これを実行すると、最終カウントが2000(それぞれの魔法使いから1000のインクリメント)であることを期待するかもしれません。しかし、驚き!結果はしばしば2000未満です。これは、私たちの魔法使いがお互いの足を引っ張っているためです。彼らは同時にカウンタをインクリメントしようとしているため、インクリメントが失われることがあります。
再入ロックを使用したマルチスレッド
それでは、私たちのカウンタに再入ロックの魔法を振りかけましょう:
import java.util.concurrent.locks.ReentrantLock;
public class MagicalCounterWithLock {
private int count = 0;
private ReentrantLock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
}
これを分解すると:
-
ReentrantLock
オブジェクトlock
を作成します。 -
increment
メソッド内で、カウンタをインクリメントする前にlock.lock()
を呼び出します。 - try-finallyブロックを使用して、エラーが発生しても必ずアンロックするようにします。
- インクリメントした後、finallyブロック内で
lock.unlock()
を呼び出します。
この新しいMagicalCounterWithLockを使用してWizardThreadテストを実行すると、最終カウントが常に2000になります。私たちの魔法使いは今、きちんと順番を守っています!
再入ロックの公平性
ReentrantLockには、もう一つの技があります。公平性パラメータを設定することができます:
ReentrantLock fairLock = new ReentrantLock(true);
公平性をtrueに設定すると、ロックは最も長く待っているスレッドにアクセスを許可します。まるで魔法使いたちの適切な順番を作るようなものです!
以下にその使用方法を示します:
public class FairMagicalCounter {
private int count = 0;
private ReentrantLock fairLock = new ReentrantLock(true);
public void increment() {
fairLock.lock();
try {
count++;
} finally {
fairLock.unlock();
}
}
public int getCount() {
return count;
}
}
これにより、複数の魔法使いがカウンタをインクリメントするのを待っている場合、最も長く待っている魔法使いが次に進むことができます。
結論
そして、若い魔法使いの皆さん!私たちはJavaの再入モニタの魔法の世界を旅しました。私たちは、マルチスレッド環境で共有リソースを保護する方法を学びました。そして、魔法のカウンタ(そして他の共有オブジェクト)が正しくインクリメントされるようにしました。
reentrantモニタは強力な魔法ですが、慎重に使用するべきです。共有リソースへの同時アクセスを管理するのに非常に役立ちますが、過度な使用はパフォーマンスが低下したり、デッドロック(魔法使いがお互いのロックを待ち続ける状況)を引き起こす可能性があります。
これらの魔法(コード例)を練習し、間もなくあなたもマルチスレッドの魔法を自在に使えるようになるでしょう!ハッピーコーディング、そしてあなたのスレッドが常に調和するよう祈っています!
Credits: Image by storyset