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
这将允许您重用线程,而不是每次运行作业时都生成一堆新线程。完成服务将在等待作业完成时执行阻塞。还要注意,结果
列表将按完成顺序排列
你也可以