通过一个例子了解java中的phaser

时间:2015-08-12 04:26:07

标签: java-8 phaser

我试图在java中理解Phaser。我写了一个例子,提前等待其他各方到达。

据我所知,phaser用作可重复使用的线程同步(不同于CountdownLatch,它不可重用)屏障具有屏障动作(与用于共享状态的Cyclicbarrier不同,Phaser不必共享状态在屏障行动)。如果我错了,请纠正我。

所以,在我的例子中,我试图在一定数量的聚会/线程到达障碍后在每个线程中执行一些随机的加法和减法代码。我做错了什么?

import static java.lang.String.*;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Phaser;
import java.util.stream.IntStream;

public class PhaserUsage implements Callable<String> {

    private static final int THREAD_POOL_SIZE = 10;
    private final Phaser phaser;

    private PhaserUsage(Phaser phaser) {
        this.phaser = phaser;
    }

    public static void main(String a[]) {
        ExecutorService execService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
        CompletionService<String> completionService = new ExecutorCompletionService<>(execService);

        Phaser phaser = new Phaser(1);
        IntStream.range(0, THREAD_POOL_SIZE)
                .forEach(nbr -> completionService.submit(new PhaserUsage(phaser)));

        execService.shutdown();

         try {
             while (!execService.isTerminated()) {
                String result = completionService.take().get();
                System.out.println(format("Result is: %s", result));
             }
          } catch (ExecutionException | InterruptedException e) {
             e.printStackTrace();
          }
    }

    @Override
    public String call() {
        String threadName = Thread.currentThread().getName();
        System.out.println(format("Registering...%s",threadName));
        phaser.register();
        System.out.println(format("Arrive and await advance...%s",threadName));
        phaser.arriveAndAwaitAdvance(); // await all creation
        int a = 0, b = 1;
        Random random = new Random();
        for (int i = 0; i < random.nextInt(10000000); i++) {
            a = a + b;
            b = a - b;
        }
        System.out.println(format("De-registering...%s",threadName));
        phaser.arriveAndDeregister();
        return format("Thread %s results: a = %s, b = %s", threadName, a, b);
    }
}

3 个答案:

答案 0 :(得分:2)

您使用值1初始化Phaser:

Phaser phaser = new Phaser(1);

这意味着您的主线程是您正在等待的线程之一,但它从不调用arrival()。

当你的线程数被修复时,你应该用线程号初始化Phaser,并删除register()调用。

答案 1 :(得分:2)

问题是您无法从正在注册的任务中调用phaser.register()。使用移相器时,请始终遵循以下两条规则:

  1. 只有注册的任务才能注册其他任务。这意味着任务无法自行注册。
  2. 所有已注册的任务必须在结束前取消注册。一个好的做法是使用最终取消注册的finally块周围的移相器包装代码(参见示例)。
  3. 这是您的固定程序(注意创建移相器的行):

    import static java.lang.String.*;
    
    import java.util.Random;
    import java.util.concurrent.*;
    import java.util.stream.IntStream;
    
    public class PhaserUsage implements Callable<String> {
    
        private static final int THREAD_POOL_SIZE = 10;
        private final Phaser phaser;
    
        private PhaserUsage(Phaser phaser) {
            this.phaser = phaser;
        }
    
        public static void main(String a[]) {
            ExecutorService execService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
            CompletionService<String> completionService = new ExecutorCompletionService<>(execService);
    
            // since we know beforehand how many tasks we have, initialize the
            // number of participants in the constructor; other wise register
            // *before* launching the task
            Phaser phaser = new Phaser(THREAD_POOL_SIZE);
    
            IntStream.range(0, THREAD_POOL_SIZE)
                    .forEach(nbr -> completionService.submit(new PhaserUsage(phaser)));
    
            execService.shutdown();
    
             try {
                 while (!execService.isTerminated()) {
                    String result = completionService.take().get();
                    System.out.println(format("Result is: %s", result));
                 }
              } catch (ExecutionException | InterruptedException e) {
                 e.printStackTrace();
              }
        }
    
        @Override
        public String call() {
            String threadName = Thread.currentThread().getName();
            System.out.println(format("Arrive and await advance...%s",threadName));
            phaser.arriveAndAwaitAdvance(); // await all creation
            int a = 0, b = 1;
            Random random = new Random();
            for (int i = 0; i < random.nextInt(10000000); i++) {
                a = a + b;
                b = a - b;
            }
            System.out.println(format("De-registering...%s",threadName));
            phaser.arriveAndDeregister();
            return format("Thread %s results: a = %s, b = %s", threadName, a, b);
        }
    }
    

答案 2 :(得分:0)

以下是没有pha​​ser.register()的工作代码:

import static java.lang.String.*;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Phaser;
import java.util.stream.IntStream;

public class PhaserUsage implements Callable<String> {

    private static final int THREAD_POOL_SIZE = 10;
    private Phaser phaser;

    private PhaserUsage(Phaser phaser) {
        this.phaser = phaser;
    }

    public static void main(String a[]) {
        ExecutorService execService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
        CompletionService<String> completionService = new ExecutorCompletionService<>(execService);

        Phaser phaser = new Phaser(1);
        IntStream.range(0, THREAD_POOL_SIZE)
                .forEach(nbr -> completionService.submit(new PhaserUsage(phaser)));

        execService.shutdown();

         try {
             while (!execService.isTerminated()) {
                String result = completionService.take().get();
                System.out.println(format("Result is: %s", result));
             }
          } catch (ExecutionException | InterruptedException e) {
             e.printStackTrace();
          }
    }

    @Override
    public String call() {
        String threadName = Thread.currentThread().getName();
        System.out.println(format("Registering...%s",threadName));
        //phaser.register();
        System.out.println(format("Arrive and await advance...%s",threadName));
        phaser.arriveAndAwaitAdvance(); // await all creation
        int a = 0, b = 1;
        Random random = new Random();
        for (int i = 0; i < random.nextInt(10000000); i++) {
            a = a + b;
            b = a - b;
        }
        System.out.println(format("De-registering...%s",threadName));
        phaser.arriveAndDeregister();
        return format("Thread %s results: a = %s, b = %s", threadName, a, b);
    }
}