Java 移相器同步使用 一般问题

Java 移相器同步使用 一般问题,java,multithreading,phaser,Java,Multithreading,Phaser,众所周知,相位器可用于同步Niklas Schlimm和中提到的所有任务的开始时间 Niklas绘制了一幅非常容易理解的同步图像: |Phaser |Phaser |Phaser | Task 1 | ------> | ------> | ------> | ... Task 2 | ------> | ------> | ------> | ... ... 现在假设存在任务的层次结构: |Pha

众所周知,相位器可用于同步Niklas Schlimm和中提到的所有任务的开始时间

Niklas绘制了一幅非常容易理解的同步图像:

         |Phaser   |Phaser   |Phaser   |  
Task 1   | ------> | ------> | ------> | ...
Task 2   | ------> | ------> | ------> | ...
...
现在假设存在任务的层次结构:

         |Phaser   |Phaser   |Phaser   |Phaser   |Phaser   |Phaser   |Phaser   |   ...
Master   |         |         | ------> |         |         | ------> |         |   ...
Task 1.1 | ----------------> |         | ----------------> |         | ----------> ...
Task 1.2 | ----------------> |         | ----------------> |         | ----------> ...
...      |         |         |         |         |         |         |         |   ...
Task 2.1 | ------> |         |         | ------> |         |         | ------> |   ...
Task 2.2 | ------> |         |         | ------> |         |         | ------> |   ...
...      |         |         |         |         |         |         |         |   ...
Task 3.1 |         | ------> |         |         | ------> |         |         |   ...
Task 3.2 |         | ------> |         |         | ------> |         |         |   ...
...      |         |         |         |         |         |         |         |   ...
因此,依赖关系树如下所示:

                      Master
           /-----------/  \-----------\
           |                        Task 2 
         Task 1                       |
           |                        Task 3
           \-----------\  /-----------/
                      Master'
在一般情况下,需要解决依赖关系树(比如在游戏管道中,有些是AI/游戏逻辑/渲染任务)。幸运的是,有一个“大”同步点,树是固定的(但不是参与方的数量)。用几个相量求解是很简单的。但是否可以只使用一个相位器

一个特例 具体来说,我制作了一个程序来解决以下问题

         |phasers[0]|phasers[1]|phasers[2]|phasers[0]|phasers[1]|phasers[2]| ...
Task 1   | -------> |          |          | -------> |          |          | ...
Task 2   | -------> |          |          | -------> |          |          | ...
Task 3   |          |          | -------> |          |          | -------> | ...
Task 4   |          | -------> |          |          | -------> |          | ...
代码如下:

public class VolatileTester {

    private int a = 0, b = 0;       // change to volatile here
    private int c = 0;

    private final int TEST_COUNT = 100_000;
    private int[] testResult = new int[TEST_COUNT];

    private static void printResult(int[] result) {
        final Map<Integer, Integer> countMap = new HashMap<>();
        for (final int n : result) {
            countMap.put(n, countMap.getOrDefault(n, 0) + 1);
        }

        countMap.forEach((n, count) -> {
            System.out.format("%d -> %d%n", n, count);
        });
    }

    private void runTask1() {
        a = 5;
        b = 10;
    }

    private void runTask2() {
        if (b == 10) {
            if (a == 5) {
                c = 1;
            } else {
                c = 2;
            }
        } else {
            if (a == 5) {
                c = 3;
            } else {
                c = 4;
            }
        }
    }

    private void runTask3() {
        // "reset task"
        a = 0;
        b = 0;
        c = 0;
    }

    private static class PhaserRunner implements Runnable {
        private final Phaser loopStartPhaser;
        private final Phaser loopEndPhaser;
        private final Runnable runnable;

        public PhaserRunner(Phaser loopStartPhaser, Phaser loopEndPhaser, Runnable runnable) {
            this.loopStartPhaser = loopStartPhaser;
            this.loopEndPhaser = loopEndPhaser;
            this.runnable = runnable;
        }

        @Override
        public void run() {
            while (loopStartPhaser.arriveAndAwaitAdvance() >= 0) {
                runnable.run();
                loopEndPhaser.arrive();
            }
        }
    }

    void runTest() throws InterruptedException {
        final Phaser[] phasers = new Phaser[]{new Phaser(3), new Phaser(3), new Phaser(2)};

        final Thread[] threads = new Thread[]{
                // build tree of dependencies here
                new Thread(new PhaserRunner(phasers[0], phasers[1], this::runTask1)),
                new Thread(new PhaserRunner(phasers[0], phasers[1], this::runTask2)),
                new Thread(new PhaserRunner(phasers[2], phasers[0], this::runTask3))
        };

        try {
            for (Thread thread : threads) {
                thread.start();
            }

            phasers[0].arrive();        // phaser of last round

            for (int i = 0; i < TEST_COUNT; i++) {
                phasers[1].arriveAndAwaitAdvance();

                // Task4 here
                testResult[i] = c;

                phasers[2].arrive();
            }
        } finally {
            for (Phaser phaser : phasers) {
                phaser.forceTermination();
            }
        }

        for (Thread thread : threads) {
            thread.join();
        }

        printResult(testResult);
    }
}
公共类VolatileTester{
private int a=0,b=0;//此处更改为volatile
私有int c=0;
私人最终整数测试计数=100 000;
私有int[]testResult=newint[TEST_COUNT];
私有静态void打印结果(int[]结果){
final Map countMap=new HashMap();
用于(最终整数n:结果){
countMap.put(n,countMap.getOrDefault(n,0)+1);
}
countMap.forEach((n,count)->{
System.out.format(“%d->%d%n”,n,count);
});
}
私有void runTask1(){
a=5;
b=10;
}
私有void runTask2(){
如果(b==10){
如果(a==5){
c=1;
}否则{
c=2;
}
}否则{
如果(a==5){
c=3;
}否则{
c=4;
}
}
}
私有void runTask3(){
//“重置任务”
a=0;
b=0;
c=0;
}
私有静态类PhaserRunner实现可运行{
专用最终相位器回路起始相位器;
专用最终相位器环端相位器;
私人最终可运行;
公共相器运行器(相器回路启动相器、相器回路结束相器、可运行可运行){
this.loopStartPhaser=loopStartPhaser;
this.loopEndPhaser=loopEndPhaser;
this.runnable=runnable;
}
@凌驾
公开募捐{
while(loopStartPhaser.arriveandWaitAdvance()>=0){
runnable.run();
loopEndPhaser.arrival();
}
}
}
void runTest()引发InterruptedException{
最终相位器[]相位器=新相位器[]{新相位器(3)、新相位器(3)、新相位器(2)};
最终螺纹[]螺纹=新螺纹[]{
//在此构建依赖关系树
新线程(新的PhaserRunner(phasers[0],phasers[1],this::runTask1)),
新线程(新的PhaserRunner(phasers[0],phasers[1],this::runTask2)),
新线程(新的PhaserRunner(phasers[2],phasers[0],this::runTask3))
};
试一试{
用于(线程:线程){
thread.start();
}
移相器[0]。到达();//上一轮的移相器
对于(int i=0;i

您可以看到使用了多个
相位器
s。是保留多个相位器(如上所述)更好,还是只使用一个大相位器更好?或者推荐使用Java中的任何其他同步方法?

是的,您可以使用一个
移相器
CyclicBarrier
具有在每个循环后运行的
RUNABLE BARRIER动作
Phaser
支持类似的功能,可以覆盖
onAdvance

当给定阶段的最后一方到达时,将执行可选操作 已执行,且阶段进展。这些操作由 触发一个阶段性推进的一方,并通过覆盖 方法onAdvance(int,int),它还控制终止。 重写此方法类似于,但比, 为自行车手提供障碍动作

所以本质上

Phaser phaser = new Phaser() {
    protected boolean onAdvance(int phase, int parties) {
        // Signal Master thread to perform its task and wait for it to finish
    }
};

应用程序中的所有任务都以分步方式进行,这意味着一个单相器就足够了。要求是任务可以周期性地跳过阶段,例如,对于每三个阶段,给定的任务应该运行两个阶段,然后跳过一个阶段(对于一个阶段是空闲的)。总之

  • 任务应在每个工作步骤之前执行
    arriveandwaitadvance()
  • 任务应该只调用
    arriveandwaitadvance()
    跳过一个阶段
为此,每个任务都可以使用一个布尔数组,在示例中称为
enabled
,该数组指定它是否在给定的阶段号启用。 通过使用模块代数(
启用[phase%enabled.length]
),我们可以定义循环模式。例如,为了指定一个任务应该运行三个刻度中的一个,我们将
启用
声明为
新布尔[]{true,false,false}

请记住,在任务中,无论他们是否执行任何实际工作,都必须推进该阶段

我相应地修改了您的示例:

import java.util.concurrent.*;
import java.util.*;

public class VolatileTester {

    private int a = 0, b = 0;       // change to volatile here
    private int c = 0;

    private final int TEST_COUNT = 100;
    private int[] testResult = new int[TEST_COUNT];

    private static void printResult(int[] result) {
        final Map<Integer, Integer> countMap = new HashMap<>();
        for (final int n : result) {
            countMap.put(n, countMap.getOrDefault(n, 0) + 1);
        }

        countMap.forEach((n, count) -> {
            System.out.format("%d -> %d%n", n, count);
        });
    }

    private void runTask1() {
        a = 5;
        b = 10;
    }

    private void runTask2() {
        if (b == 10) {
            if (a == 5) {
                c = 1;
            } else {
                c = 2;
            }
        } else {
            if (a == 5) {
                c = 3;
            } else {
                c = 4;
            }
        }
    }

    private void runTask3() {
        // "reset task"
        a = 0;
        b = 0;
        c = 0;
    }

    private static class PhaserRunner implements Runnable {
        private final Phaser phaser;
        private final Runnable runnable;
        private boolean[] enabled;

        public PhaserRunner(Phaser phaser, boolean[] enabled, Runnable runnable) {
            this.phaser = phaser;
            this.runnable = runnable;
            this.enabled = enabled;
        }

        @Override
        public void run() {
            int phase;
            for (;;) {
                phase = phaser.arriveAndAwaitAdvance();
                if (phase < 0) {
                    break;
                } else if (enabled[phase % enabled.length]) {
                    System.out.println("I'm running: " + Thread.currentThread());
                    runnable.run();
                }
            }
        }
    }

    public void runTest() throws InterruptedException {
        final Phaser phaser = new Phaser(4);

        final Thread[] threads = new Thread[]{
                // build tree of dependencies here
                new Thread(new PhaserRunner(phaser, new boolean[]{true, false, false}, this::runTask1), "T1"),
                new Thread(new PhaserRunner(phaser, new boolean[]{false, false, true}, this::runTask2), "T2"),
                new Thread(new PhaserRunner(phaser, new boolean[]{false, true, false}, this::runTask3), "T3")
        };

        try {
            for (Thread thread : threads) {
                thread.start();
            }

            for (int i = 0; i < TEST_COUNT; i++) {
                testResult[i] = c;
                phaser.arriveAndAwaitAdvance();
            }
        } finally {
            phaser.forceTermination();
        }

        for (Thread thread : threads) {
            thread.join();
        }

        printResult(testResult);
    }

    public static void main(String[]args) throws Exception {
        new VolatileTester().runTest();
    }
}
import java.util.concurrent.*;
导入java.util.*;
公共类挥发仪{
private int a=0,b=0;//此处更改为volatile
私有int c=0;
私人最终整数测试计数=100;
私有int[]testResult=newint[TEST_COUNT];
私有静态void打印结果(int[]结果){
final Map countMap=new HashMap();
用于(最终整数n:结果){
countMap.put(n,countMap.getOrDefault(n,0)+1);
}