ReentrantLock
ReentrantLock は synchronized を使用したロックです。1.5から追加されました。
基本的な使い方:
final Lock lock = new ReentrantLock(); try { lock.lock(); // ロックする。 // 処理 } finally { lock.unlock(); // ロックを解放。 }
もうちょっと長いサンプル:
class WithLock implements Runnable { /**ロック*/ final Lock lock; /**ロックしてから実行する処理*/ final Runnable procedure; /** * コンストラクタ * @param lock ロック * @param procedure ロックしてから実行する処理 */ WithLock ( Lock lock, Runnable procedure ) { this.lock = lock; this.procedure = procedure; } public void run () { try { lock.lock(); // ロックする。 procedure.run(); } finally { lock.unlock(); // ロックを解放。 } } } class Say implements Runnable { /**名前*/ final String name; /** * コンストラクタ * @param name 名前 */ Say ( String name ) { this.name = name; } public void run () { try { System.out.println( name ); Thread.sleep( 100 ); System.out.println( name + "!" ); Thread.sleep( 100 ); System.out.println( name + "!!" ); } catch ( InterruptedException e ) { // 誰も止めない。 } } } final Lock lock = new ReentrantLock(); String[] names = new String[]{ "shiro", "kuro", "tora", "mii" }; // ロックしない。// バラバラになる。 for ( int i = 0; i < names.length; i++ ) { Runnable run = new Say( names[i] ); new Thread( run ).start(); } Thread.sleep( 1000 ); System.out.println( "---" ); // ロックする。// 整列する。 for ( int i = 0; i < names.length; i++ ) { Runnable run = new WithLock ( lock, new Say( names[i] ) ); new Thread( run ).start(); }
実行すると、ロックした場合は名前がバラバラにならず、排他制御ができているのがわかります。
出力:
shiro kuro tora mii mii! tora! kuro! shiro! mii!! shiro!! kuro!! tora!!
-
- -
lockするスレッドとunlockするスレッドは同じでなければなりません。
別スレッドでunlockを実行するとエラーになります。
final Lock lock = new ReentrantLock(); try { lock.lock(); // 処理 } finally { // 別スレッドでは解放できない。 new Thread() { public void run() { lock.unlock(); // java.lang.IllegalMonitorStateExceptionが発生。 } }.start(); }