Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 具有多线程的CyclicBarrier性能不佳:树状同步结构是否是一种替代方案?_Java_Multithreading_Performance_Concurrency - Fatal编程技术网

Java 具有多线程的CyclicBarrier性能不佳:树状同步结构是否是一种替代方案?

Java 具有多线程的CyclicBarrier性能不佳:树状同步结构是否是一种替代方案?,java,multithreading,performance,concurrency,Java,Multithreading,Performance,Concurrency,我们的应用程序要求所有工作线程在定义的点上同步。为此,我们使用了CyclicBarrier,但它的伸缩性似乎不好。对于8个以上的线程,同步开销似乎超过了多线程的好处。(但是,我无法用测量数据支持这一点。) 编辑:同步发生的频率非常高,大约为100k到1M次 如果多个线程的同步是“困难的”,那么它是否有助于构建同步树?线程1等待2和3,2和3依次等待4+5和6+7,以此类推。;完成后,螺纹2和3等待螺纹1,螺纹4和5等待螺纹2,以此类推 1 | \ 2 3 |\ |\ 4 5 6 7 这样

我们的应用程序要求所有工作线程在定义的点上同步。为此,我们使用了
CyclicBarrier
,但它的伸缩性似乎不好。对于8个以上的线程,同步开销似乎超过了多线程的好处。(但是,我无法用测量数据支持这一点。)

编辑:同步发生的频率非常高,大约为100k到1M次

如果多个线程的同步是“困难的”,那么它是否有助于构建同步树?线程1等待2和3,2和3依次等待4+5和6+7,以此类推。;完成后,螺纹2和3等待螺纹1,螺纹4和5等待螺纹2,以此类推

1
| \
2   3
|\  |\
4 5 6 7
这样的设置会减少同步开销吗?如果有任何建议,我将不胜感激


另请参见此特色问题:

您以一种微妙错误的方式思考问题,这往往会导致非常糟糕的编码。您不希望等待线程,而是希望等待工作完成


也许最有效的方法是共享、可等待的柜台。进行新工作时,增加计数器并向计数器发送信号。完成工作后,减小计数器的值。如果没有工作要做,就在柜台等。如果您将计数器降到零,请检查您是否可以进行新的工作。

您正在以一种微妙的错误方式思考问题,这往往会导致非常糟糕的编码。您不希望等待线程,而是希望等待工作完成


也许最有效的方法是共享、可等待的柜台。进行新工作时,增加计数器并向计数器发送信号。完成工作后,减小计数器的值。如果没有工作要做,就在柜台等。如果你把计数器降到零,检查你是否能做新的工作。

如果我理解正确,你是在尝试将你的解决方案分解成几个部分,分别解决,但同时解决,对吗?然后让当前线程等待这些任务?您需要使用类似于fork/join模式的东西

List<CustomThread> threads = new ArrayList<CustomThread>();
for (Something something : somethings) {
    threads.add(new CustomThread(something));
}
for (CustomThread thread : threads) {
    thread.start();
}
for (CustomThread thread : threads) {
    thread.join(); // Blocks until thread is complete
}
List<Result> results = new ArrayList<Result>();
for (CustomThread thread : threads) {
    results.add(thread.getResult());
}
// do something with results.
然后,要使用它,请使用固定大小的线程池创建一个
ExecutorService
。这将限制您同时运行的作业数量,这样您就不会意外地对系统进行线程轰炸。这是你的主要工作:

public class MainJob extends Thread {

    // Adjust the pool to the appropriate number of concurrent
    // threads you want running at the same time
    private static final ExecutorService pool = Executors.newFixedThreadPool(30);
    private final List<Input> inputs;

    public MainJob(List<Input> inputs) {
        super("MainJob")
        this.inputs = new ArrayList<Input>(inputs);
    }

    public void run() {
        CompletionService<Result> compService = new ExecutorCompletionService(pool);
        List<Result> results = new ArrayList<Result>();
        int submittedJobs = inputs.size();
        for (Input input : inputs) {
            // Starts the job when a thread is available
            compService.submit(new SubJob(input)); 
        }
        for (int i = 0; i < submittedJobs; i++) {
            // Blocks until a job is completed
            results.add(compService.take())
        }
        // Do something with results
    }
}
public类MainJob扩展线程{
//将池调整为适当的并发数
//要同时运行的线程
私有静态最终执行器服务池=Executors.newFixedThreadPool(30);
私人最终清单投入;
公共主作业(列表输入){
超级(“主要工作”)
this.inputs=新的ArrayList(输入);
}
公开募捐{
CompletionService compService=新的ExecutionCompletionService(池);
列表结果=新建ArrayList();
int submittedJobs=inputs.size();
用于(输入:输入){
//当线程可用时启动作业
compService.submit(新子对象(输入));
}
对于(int i=0;i
这将允许您重用线程,而不是每次运行作业时都生成一堆新线程。完成服务将在等待作业完成时执行阻塞。还要注意,
结果
列表将按完成顺序排列

您还可以使用
Executors.newCachedThreadPool
,它创建一个没有上限的池(就像使用
Integer.MAX_VALUE
)。如果线程可用,它将重用线程;如果池中的所有线程都在运行作业,它将创建一个新线程。如果您以后开始遇到死锁(因为固定线程池中有太多作业等待,子作业无法运行和完成),这可能是可取的。这将至少限制正在创建/销毁的线程数

最后,您需要手动关闭
ExecutorService
,可能是通过关闭钩子,否则它包含的线程将不允许JVM终止


希望这有帮助/有意义。

如果我理解正确,您试图将您的解决方案分解为多个部分,分别但同时解决,对吗?然后让当前线程等待这些任务?您需要使用类似于fork/join模式的东西

List<CustomThread> threads = new ArrayList<CustomThread>();
for (Something something : somethings) {
    threads.add(new CustomThread(something));
}
for (CustomThread thread : threads) {
    thread.start();
}
for (CustomThread thread : threads) {
    thread.join(); // Blocks until thread is complete
}
List<Result> results = new ArrayList<Result>();
for (CustomThread thread : threads) {
    results.add(thread.getResult());
}
// do something with results.
然后,要使用它,请使用固定大小的线程池创建一个
ExecutorService
。这将限制您同时运行的作业数量,这样您就不会意外地对系统进行线程轰炸。这是你的主要工作:

public class MainJob extends Thread {

    // Adjust the pool to the appropriate number of concurrent
    // threads you want running at the same time
    private static final ExecutorService pool = Executors.newFixedThreadPool(30);
    private final List<Input> inputs;

    public MainJob(List<Input> inputs) {
        super("MainJob")
        this.inputs = new ArrayList<Input>(inputs);
    }

    public void run() {
        CompletionService<Result> compService = new ExecutorCompletionService(pool);
        List<Result> results = new ArrayList<Result>();
        int submittedJobs = inputs.size();
        for (Input input : inputs) {
            // Starts the job when a thread is available
            compService.submit(new SubJob(input)); 
        }
        for (int i = 0; i < submittedJobs; i++) {
            // Blocks until a job is completed
            results.add(compService.take())
        }
        // Do something with results
    }
}
public类MainJob扩展线程{
//将池调整为适当的并发数
//要同时运行的线程
私有静态最终执行器服务池=Executors.newFixedThreadPool(30);
私人最终清单投入;
公共主作业(列表输入){
超级(“主要工作”)
this.inputs=新的ArrayList(输入);
}
公开募捐{
CompletionService compService=新的ExecutionCompletionService(池);
列表结果=新建ArrayList();
int submittedJobs=inputs.size();
用于(输入:输入){
//当线程可用时启动作业
compService.submit(新子对象(输入));
}
对于(int i=0;i
这将允许您重用线程,而不是每次运行作业时都生成一堆新线程。完成服务将在等待作业完成时执行阻塞。还要注意,
结果
列表将按完成顺序排列

你也可以