wait()とnotify()を使用して、スレッド間コラボレーションを実現します
1。Wait()and Notify()/NotifyAll()
Sleep()とHight()が呼び出されると、ロックは解放されず、Calling wait()はロックを解放します。このようにして、別のタスク(スレッド)が現在のオブジェクトのロックを取得して、同期された方法を入力できます。 wait()からnotify()/notifyall()を介して実行を再開できます。
wait()、notify()、およびnotifyall()は、同期制御方法または同期ブロックでのみ呼び出すことができます。これらの方法が非同期メソッドで呼び出される場合、RuntimeでIllegalMonitorStateExceptionの例外がスローされます。
2。単一のスレッドで複数のスレッドの目覚めをシミュレートする
スレッド間のコラボレーションをシミュレートします。ゲームクラスには、2つの同期メソッドが()とgo()を備えています。フラグの開始は、現在のスレッドにwait()が必要かどうかを判断するために使用されます。ゲームクラスのインスタンスは、最初にすべてのAtheleクラスインスタンスを開始し、Wait()状態を入力します。しばらくしてから、フラグビットを変更し、すべてのAtheleスレッドを待機状態に変更します。
game.java
パッケージの並行性; Import java.util.collection; import java.util.collections; import java.util.hashset; Import java.util.iterator; import java.util.set; class athleteは実行可能{private final int id;プライベートゲームゲーム。パブリックアスリート(int id、ゲームゲーム){this.id = id; this.game = game; } public boolean equals(object o){if(!(o instanceof of))return false;アスリートアスリート=(アスリート)O; return id == athlete.id; } public String toString(){return "Athlete <" + id + ">"; } public int hashcode(){return new Integer(id).hashcode(); } public void run(){try {game.prepare(this); } catch(arturtedexception e){system.out.println(this + "quit the game"); }}}パブリッククラスゲーム実装runnable {private set <Athlet> players = new Hashset <Athlete>();プライベートブールのstart = false; public void addplayer(Athlete one){player.add(one); } public void removeplayer(Athlete one){player.remove(one); } public collection <Athlete> getPlayers(){return collections.unmodifiableset(players); } public void prepare(アスリートアスリート)Sthrows arturnedexception {System.out.println(Athlete + "Ready!");同期(this){while(!start)wait(); if(start)system.out.println(Athlete + "go!"); }} public synchronized void go(){notifyall(); } public void ready(){iterator <Athlet> iter = getPlayers()。iterator(); while(iter.hasnext())new Stread(iter.next())。start(); } public void run(){start = false; System.out.println( "Ready ..."); System.out.println( "Ready ..."); System.out.println( "Ready ...");準備ができて(); start = true; System.out.println( "go!");行く(); } public static void main(string [] args){game game = new Game(); for(int i = 0; i <10; i ++)game.addplayer(new Athlete(i、game));新しいスレッド(game).start(); }}結果:
準備ができました...準備...アスリート<0>準備ができました!アスリート<1>準備完了!アスリート<2>レディ!アスリート<3>レディ!レディ!アスリート<5>レディ!アスリート<6>レディ!アスリート!アスリート<7>レディ! Go!Athlete <5> Go!Athlete <4> Go!Athlete <3> Go!Athlete <2> Go!Athlete <1> Go!Athlete <0> Go!
3.忙しい待機プロセスをシミュレートします
Myobjectクラスのインスタンスはオブザーバーです。観察イベントが発生すると、モニタークラスのインスタンス(フラグを変更する方法)に通知します。このモニタークラスのインスタンスは、待機によってフラグビットが変化するかどうかを常にチェックします。
busywaiting.java
java.util.concurrent.timeunit; class myobject runnable {private Monitor Monitor; public Myobject(Monitor Monitor){this.monitor = Monitor; } public void run(){try {timeunit.seconds.sleep(3); System.out.println( "I'm Going。"); monitor.gotmessage(); } catch(arturnedexception e){e.printstacktrace(); }}} classモニターはrunnable {private volatile boolean go = false; public void gotmessage()throws arturtedexception {go = true; } public void watch(){while(go == false); system.out.println( "彼は行った。"); } public void run(){wathing(); }} public class busywaiting {public static void main(string [] args){Monitor Monitor = new Monitor(); myobject o = new Myobject(Monitor);新しいスレッド(o).start();新しいスレッド(モニター).start(); }}結果:
私は行きます。彼は行っています。
4。wait()とnotify()を使用して、上記の例を書き直します
次の例では、byway()を通じて忙しい待機メカニズムに置き換えられます。通知メッセージが受信されたら、現在のモニタークラススレッドに通知します。
wait.java
パッケージCONSCURRENCY.WAIT; IMPORT JAVA.UTIL.CONCURRENT.TIMEUNIT;クラスMYOBJECT実装runnable {private Monitor; public Myobject(Monitor Monitor){this.monitor = Monitor; }定期的にスレッドを開始します
指定された時間の後にスレッドを開始する2つの方法を次に示します。まず、java.util.concurrent.delayqueueを介して実装されています。第二に、java.util.concurrent.scheduledthreadpoolexecutorを介して実装されています。
1。Java.util.concurrent.delayqueue
クラスの遅延は、遅延の有効期限が切れたときにのみ要素を抽出できる、無制限のブロッキングキューです。遅延インターフェイスを要素として実装するインスタンスを受け入れます。
<< Interface >> delayed.java
パッケージjava.util.concurrent;インポートjava.util。*; public interface delayed extends carplaint <delayed> {long getdelay(timeunit unit);}getDelay()は、特定の時間単位で表されるこのオブジェクトに関連付けられた残りの遅延時間を返します。このインターフェイスの実装は、このインターフェイスのgetDelayメソッドと一貫した種類を提供する比較方法を定義する必要があります。
遅延キューのヘッドは、遅延が期限切れになった後最長のストレージ時間を持つ遅延要素です。有効期限は、getdelay(timeunit.nanoconds)の要素のメソッドが0以下の値を0以下に返す場合に発生します。
2。時間遅延特性を備えたキューを設計します
クラスの遅延タスカーは、遅延<delayedtask>キューを維持します。ここで、遅延タスクが遅延インターフェイスを実装し、内部クラスによって定義されます。外部クラスと内部クラスの両方が実行可能なインターフェイスを実装します。外部クラスの場合、その実行方法は、定義された時間に従ってキュー内のタスクを順番に取り出し、これらのタスクは内部クラスのインスタンスです。内部クラスの実行方法は、各スレッドの特定のロジックを定義します。
このデザインの本質は、時間の特性を持つスレッドタスクのリストを定義することであり、リストには任意の長さを持つことができます。タスクを追加するたびに起動時間を指定します。
delayedtasker.java
パッケージcom.zj.timedtask; import static java.util.concurrent.timeunit.seconds; Import static java.util.concurrent.timeunit.nanoseconds; Import java.util.collection; Import java.util.collection java.util.concurrent.delayqueue; Import java.util.concurrent.delayed; import java.util.concurrent.executorservice; Import java.util.concurrent.executors; Import java.util.concurrent.ime new Delayqueue <DelayedTask>(); public void addtask(delayedtask e){queue.put(e); } public void removetask(){queue.poll(); } public collection <delayedtask> getAlltasks(){return collections.unmodifiablecollection(queue); } public int getTaskQuantity(){return queue.size(); } public void run(){while(!queue.isempty())try {queue.take()。run(); } catch(arternedexception e){system.out.println( "挿入"); } system.out.println( "finish delayedtask"); } public static class delayedtaskは遅延、実行可能{private static int counter = 0;プライベートファイナルInt = counter ++;プライベートファイナルイントデルタ;プライベートファイナルロングトリガー。 public delayedtask(int delayinseconds){delta = delayinseconds; trigger = system.nanotime() + nanoconds.convert(delta、秒); } public long getDelay(timeUnit unit){return unit.convert(trigger -system.nanotime()、nanoconds); } public int compareto(delayed arg){delayedtask that =(delayedtask)arg; if(trigger <this.trigger)return -1; if(trigger> that.trigger)return 1; 0を返します。 } public void run(){// system.out.println(this); } public String toString(){return "[" + delta + "s]" + "task" + id; }} public static void main(string [] args){random rand = new Random(); executorservice exec = executors.newcachedthreadpool(); delayedtasker tasker = new delayedtasker(); for(int i = 0; i <10; i ++)tasker.addtask(new delayedtask(rand.nextint(5))); exec.execute(tasker); exec.shutdown(); }}結果:
[0S]タスク1 [0S]タスク2 [0S]タスク3 [1S]タスク6 [2S]タスク5 [3S]タスク8 [4S]タスク0 [4S]タスク4 [4S]タスク7 [4S]タスク9FinishedDelayedTask
3。java.util.concurrent.scheduledthreadpoolexecutor
このクラスは、特定の遅延後にタスク(スレッド)を実行するか、定期的にタスクを実行するようにスケジュールできます(繰り返し)。コンストラクターでは、スレッドプールのサイズを知る必要があります。主な方法は次のとおりです。
[1]スケジュール
public ScheduledFuture <?
特定の遅延後に有効になった1回限りの操作を作成および実行します。
指定:
-Interface ScheduleDexecutorServiceでスケジュールします。
パラメーター:
-command-実行されるタスク。
-delay-これから実行を遅らせる時間。
-unit-遅延パラメーターの時間単位。
戻る:
- タスクを一時停止し、そのget()メソッドが完了後にnullを返すスケジュールされたfutureを示します。
[2] scheduleatfixedrate
public ScheduledFuture <?
Runnableコマンド、Long InitialDelay、長期間、TimeUnitユニット)
特定の初期遅延後に最初に有効にされる定期操作を作成および実行し、その後の操作には特定の期間があります。つまり、InitialDelayの後に開始され、次に初期デレイ +期間の後、InitialDelay + 2 *期間などの後に始まります。タスクの実行が例外に遭遇した場合、その後の実行がキャンセルされます。それ以外の場合、プログラムのキャンセルまたは終了方法を実行することによってのみタスクを終了できます。このタスクの実行のいずれかがサイクルよりも時間がかかる場合、その後の実行は延期されますが、同時に延期されません。
指定:
-Interface ScheduleDexecutorServiceのScheduleatFixEdrate;
パラメーター:
-command-実行されるタスク。
-InitialDelay-最初の実行の遅延時間。
- 期間 - 継続的な実行間の期間。
-UNIT-初期デレイとピリオドパラメーターの時間単位。
戻る:
- 中断されたタスクのスケジュールされた顧客が完了し、そのget()メソッドがキャンセルされた後に例外をスローすることを示します。
4.時間遅延特性を持つスレッドエグゼキューターを設計します
クラスScheduleTaskedは、スレッドプールのサイズを指定できるスケジュールされたThreadPoolexcutorをアッと関連付けています。スレッドを把握し、スケジュールメソッドを介して時間を遅らせ、シャットダウン方法でスレッドプールを閉じます。特定のタスク(スレッド)のロジックには特定の柔軟性があります(以前の設計と比較して、以前の設計ではスレッドのロジックを事前に定義する必要がありますが、スレッドの特定のロジック設計は、継承または装飾によって変更できます)。
scheduletasker.java
パッケージcom.zj.timedtask;インポートjava.util.concurrent.scheduledthreadpoolexecutor; Import java.util.concurrent.timeunit; public class scheduletasker {private int corepoolsize = 10; ScheduledThreadPoolexecutorスケジューラ。 public ScheduleTasker(){Scheduler = new ScheduleDthreadPoolexecutor(corePoolsize); } public ScheduleTasker(int数量){corepoolsize =数量; scheduler = new ScheduledThreadPoolexecutor(corePoolsize); } public voidスケジュール(実行可能なイベント、長い遅延){scheduler.schedule(event、delay、timeunit.seconds); } public void shutdown(){scheduler.shutdown(); } public static void main(string [] args){scheduletasker tasker = new ScheduleTasker(); tasker.schedule(new runnable(){public void run(){system.out.println( "[1s] task 1");}}、1); tasker.schedule(new runnable(){public void run(){system.out.println( "[2s] task 2");}}、2); tasker.schedule(new runnable(){public void run(){system.out.println( "[4s] task 3");}}、4); tasker.schedule(new runnable(){public void run(){public void run(){system.out.println( "[10S]タスク4");}}、10); tasker.shutdown(); }}結果:
[1S]タスク1 [2S]タスク2 [4S]タスク3 [10S]タスク4 public void run(){try {timeunit.seconds.sleep(3); System.out.println( "I'm Going。"); monitor.gotmessage(); } catch(arturnedexception e){e.printstacktrace(); }}}クラスモニターは実行可能{private volatile boolean go = false; public synchronized void gotmessage()throws arturnedexception {go = true; notify(); } public synchronized void watching()throws arturtedexception {while(go == false)wait(); system.out.println( "彼は行った。"); } public void run(){try {whited(); } catch(arturnedexception e){e.printstacktrace(); }}} public class wait {public static void main(string [] args){Monitor Monitor = new Monitor(); myobject o = new Myobject(Monitor);新しいスレッド(o).start();新しいスレッド(モニター).start(); }}結果:
私は行きます。彼は行っています。