この質問は2年前に尋ねられましたが、言及されているリソースがあまり役に立たない(IMHO)か、リンクが無効になっています。
理解するには、いくつかの優れたチュートリアルが必要Phaser
です。javadocを読みましたが、目が眩むほどです。javadocを本当に理解するには、これらのクラスがどのように使用されるかを知っている必要があるからです。
誰か提案がありますか?
Phaserについて、私はいくつかの質問に答えました。それらを見ることは、それらのアプリケーションを理解するのに役立つかもしれません。それらは下部にリンクされています。しかし、Phaserが何をするのか、そしてなぜそれが何を解決するのかを知ることが重要である理由を理解するために。
CountdownLatchとCyclicBarrierの属性は次のとおりです
ノート:
CountdownLatch
latch.countDown();
待つ
latch.await();
必要があります)CyclicBarrier
したがって、CountdownLatchは再利用できません。毎回新しいインスタンスを作成する必要がありますが、使用可能です。CylicBarrierは再利用できますが、すべてのスレッドは各パーティがバリアに到着するのを待つ必要があります。
Phaser
スレッドがPhaserに認識されることを望む場合phaser.register()
、スレッドが呼び出すバリアに到達したときに呼び出されます。phaser.arrive()
ここで、スレッドを進めることができます。スレッドが登録されたすべてのタスクが完了するのを待ちたい場合phaser.arriveAndAwaitAdvance()
スレッドが完了していない可能性のある他の操作の完了を待機できるフェーズの概念もあります。すべてのスレッドがフェイザーのバリアに到達すると、新しいフェーズが作成されます(1ずつ増加)。
あなたは私の他の答えを見ることができます、多分それは役立つでしょう:
Phaser
少なくとも、JavaDocはかなり明確な説明を提供していると思います。これは、スレッドのバッチを同期するために使用するクラスです。つまり、バッチ内の各スレッドをに登録し、バッチ内のすべてのスレッドがに通知するまで、を使用してブロックさせることができますPhaser
。ブロックされたスレッドは実行を開始します。この待機/通知サイクルは、必要に応じて何度も繰り返すことができます。 Phaser
Phaser
彼らのサンプルコードは合理的な例を示しています(私は彼らの2文字のインデントスタイルが非常に嫌いですが):
void runTasks(List<Runnable> tasks) {
final Phaser phaser = new Phaser(1); // "1" to register self
// create and start threads
for (final Runnable task : tasks) {
phaser.register();
new Thread() {
public void run() {
phaser.arriveAndAwaitAdvance(); // await all creation
task.run();
}
}.start();
}
// allow threads to start and deregister self
phaser.arriveAndDeregister();
}
Phaser
これにより、登録カウントが、のが設定され、tasks.size() + 1
タスクごとにnewが作成され、次の前進(つまり、到着が記録された時刻)Thread
までブロックされ、関連するタスクが実行されます。作成されたものも即座に開始されるため、到着が記録され てループから抜け出します。Phaser
tasks.size() + 1
Thread
Phaser
tasks.size()
への最後の呼び出しphaser.arriveAndDeregister()
は、最終的な到着を記録し、登録カウントをデクリメントして、に等しくなるようにしtasks.size()
ます。これにより、Phaser
が進み、事実上、すべてのタスクが同時に実行を開始できるようになります。これは、次のようなことを行うことで繰り返すことができます。
void runTasks(List<Runnable> tasks) {
final Phaser phaser = new Phaser(1); // "1" to register self
// create and start threads
for (final Runnable task : tasks) {
phaser.register();
new Thread() {
public void run() {
while (true) {
phaser.arriveAndAwaitAdvance(); // await all creation
task.run();
}
}
}.start();
}
// allow threads to start and deregister self
phaser.arriveAndDeregister();
}
...これは、タスクを繰り返し実行するループが追加されていることを除いて、以前と同じです。各反復呼び出しはタスクスレッドの実行を同期するため、他のすべてのタスクが最初の反復を完了し、2番目の反復を開始する準備ができていること phaser.arriveAndAwaitAdvance()
を通知するまで、task-0は2番目の反復を開始しません。Phaser
これは、実行しているタスクの実行にかかる時間が大幅に異なる場合や、高速のスレッドが低速のスレッドと同期しなくなることのないようにする場合に役立ちます。
考えられる実際のアプリケーションについては、別々のグラフィックススレッドと物理スレッドを実行するゲームを検討してください。グラフィックススレッドがフレーム6でスタックしている場合、フレーム100の物理スレッドコンピューティングデータは必要ありません。グラフィックススレッドPhaser
と物理スレッドが常に同じフレームで同時に動作するようにするための1つの可能なアプローチは、を使用することです。時間(また、一方のスレッドがもう一方のスレッドよりも大幅に遅い場合、高速のスレッドがCPUリソースを適切に生成するため、低速のスレッドがより速く追いつくことができます)。
Phaserは、CyclicBarrierとCountDownLatchの機能が多少似ていますが、両方よりも柔軟性があります。
CyclicBarrierでは、以前はコンストラクターにパーティを登録していましたが、Phaserを使用すると、いつでもパーティを登録および登録解除できる柔軟性が得られます。パーティーの登録には、次のいずれかを使用できます-
登録解除パーティには、-を使用する場合があります
register-
このフェイザーに新しい未到着のパーティを追加/登録します。戻ります
onAdvance()メソッドの呼び出しが、戻る前よりも進行中の場合、このメソッドはその完了を待つ可能性があります。このフェイザーに親があり、このフェイザーに登録されているパーティがない場合、この子フェイザーもその親に登録されます。
Phaserの使用法を示すプログラム>
import java.util.concurrent.Phaser;
public class PhaserTest {
public static void main(String[] args) {
/*Creates a new phaser with 1 registered unArrived parties
* and initial phase number is 0
*/
Phaser phaser=new Phaser(1);
System.out.println("new phaser with 1 registered unArrived parties"
+ " created and initial phase number is 0 ");
//Create 3 threads
Thread thread1=new Thread(new MyRunnable(phaser,"first"),"Thread-1");
Thread thread2=new Thread(new MyRunnable(phaser,"second"),"Thread-2");
Thread thread3=new Thread(new MyRunnable(phaser,"third"),"Thread-3");
System.out.println("\n--------Phaser has started---------------");
//Start 3 threads
thread1.start();
thread2.start();
thread3.start();
//get current phase
int currentPhase=phaser.getPhase();
/*arriveAndAwaitAdvance() will cause thread to wait until current phase
* has been completed i.e. until all registered threads
* call arriveAndAwaitAdvance()
*/
phaser.arriveAndAwaitAdvance();
System.out.println("------Phase-"+currentPhase+" has been COMPLETED----------");
//------NEXT PHASE BEGINS------
currentPhase=phaser.getPhase();
phaser.arriveAndAwaitAdvance();
System.out.println("------Phase-"+currentPhase+" has been COMPLETED----------");
/* current thread Arrives and deRegisters from phaser.
* DeRegistration reduces the number of parties that may
* be required to advance in future phases.
*/
phaser.arriveAndDeregister();
//check whether phaser has been terminated or not.
if(phaser.isTerminated())
System.out.println("\nPhaser has been terminated");
}
}
class MyRunnable implements Runnable{
Phaser phaser;
MyRunnable(Phaser phaser,String name){
this.phaser=phaser;
this.phaser.register(); //Registers/Add a new unArrived party to this phaser.
System.out.println(name +" - New unarrived party has "
+ "been registered with phaser");
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
" - party has arrived and is working in "
+ "Phase-"+phaser.getPhase());
phaser.arriveAndAwaitAdvance();
//Sleep has been used for formatting output
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//------NEXT PHASE BEGINS------
System.out.println(Thread.currentThread().getName() +
" - party has arrived and is working in "
+ "Phase-"+phaser.getPhase());
phaser.arriveAndAwaitAdvance();
phaser.arriveAndDeregister();
}
}
BulkRegister-
このフェイザーに未到着の新しいパーティのパーティ数を追加します。戻ります
onAdvance()メソッドの呼び出しが、戻る前よりも進行中の場合、このメソッドはその完了を待つ可能性があります。
ArrivateAndDeregister- 現在のスレッド(パーティ)フェイザーに到着し、フェイザーから登録解除します。登録解除により、次のフェーズに進むために将来必要になる可能性のあるパーティの数が減ります。
このフェイザーに親があり、このフェイザーに登録されているパーティがない場合、この子フェイザーもその親に登録されます。 親子フェイザーをデモンストレーションするプログラム
import java.util.concurrent.Phaser;
public class PhaserParentChildTest {
public static void main(String[] args) {
/*
* Creates a new phaser with no registered unArrived parties.
*/
Phaser parentPhaser = new Phaser();
/*
* Creates a new phaser with the given parent &
* no registered unArrived parties.
*/
Phaser childPhaser = new Phaser(parentPhaser,0);
childPhaser.register();
System.out.println("parentPhaser isTerminated : "+parentPhaser.isTerminated());
System.out.println("childPhaser isTerminated : "+childPhaser.isTerminated());
childPhaser.arriveAndDeregister();
System.out.println("\n--childPhaser has called arriveAndDeregister()-- \n");
System.out.println("parentPhaser isTerminated : "+parentPhaser.isTerminated());
System.out.println("childPhaser isTerminated : "+childPhaser.isTerminated());
}
}
Phaserの詳細については、http: //www.javamadesoeasy.com/2015/03/phaser-in-java_21.htmlをご覧ください。