Java: tutorials/explanations of jsr166y Phaser

前端 未结 3 2060
悲哀的现实
悲哀的现实 2020-12-13 10:40

This question was asked two years ago, but the resources it mentions are either not very helpful (IMHO) or links are no longer valid.

There must be some good tutoria

3条回答
  •  挽巷
    挽巷 (楼主)
    2020-12-13 11:25

    For Phaser at least, I think the JavaDoc offers a fairly clear explanation. This is a class that you would use to synchronize a batch of threads, in the sense that your can register each thread in the batch with a Phaser and then use the Phaser to have them block until every thread in the batch has notified the Phaser, at which point any blocked thread(s) will begin executing. This wait/notify cycle can repeat over and over again, as desired/required.

    Their sample code gives a reasonable example (though I very much dislike their 2-character indentation style):

    void runTasks(List 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();
     } 
    

    This sets up a Phaser with a registration count of tasks.size() + 1, and for each task creates a new Thread which will block until the next advance of the Phaser (i.e. the time at which tasks.size() + 1 arrivals have been recorded) and then run its associated task. Each Thread that is created is also instantly started, so the Phaser comes out of the loop with tasks.size() arrivals recorded.

    The final call to phaser.arriveAndDeregister() will record the final arrival, and also decrement the registration count so that it now equals tasks.size(). This causes the Phaser to advance, which in effect allows all the tasks to start running at the same time. This could be repeated by doing something like:

    void runTasks(List 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();
     }
    

    ...this is the same as before, except with the addition of a loop that causes the task to be run repeatedly. Because each iteration calls phaser.arriveAndAwaitAdvance() the execution of the task threads will be synchronized such that task-0 does not begin its second iteration until every other task has completed its first iteration and notified the Phaser that is is ready to begin its second iteration.

    This may be useful if the tasks you are running vary greatly in the amount of time they take to execute and if you want to ensure that faster threads do not get out of sync with slower ones.

    For a possible real-world application, consider a game that runs separate graphics and physics threads. You don't want to have the physics thread computing data for frame 100 if the graphics thread is stuck on frame 6, and using a Phaser is one possible approach to ensuring that the graphics and physics threads are always working on the same frame at the same time (and also that if one thread is significantly slower than the other the faster thread gracefully yields CPU resources so that hopefully the slower thread can catch up quicker).

提交回复
热议问题