在我的项目中,我一直使用CyclicBarrier
“同步”多个线程(每个线程运行相同类型的Runnable
)。就我而言,由于同步频率很高,使用CyclicBarrier
效率低下,但繁忙等待机制可能会更快。这是我到目前为止所得到的(部分遗漏):
public class MyRunnable implements Runnable {
private static AtomicInteger counter = null; // initialized to the number
// of threads
public void run() {
// do work up to a "common point"
synchronized (this) {
// decrement the counter and - if necessary - reset it
if (counter.decrementAndGet() == 0) {
counter.set(numberOfThreads);
// make all the busy waiting threads exit from the loop
for (int i = 0; i < threads.length; i++)
threads[i].interrupt();
}
}
// busy wait until all threads have reached the "common point"
while (!Thread.interrupted()) {}
}
}
不幸的是,此代码的执行情况甚至比CyclicBarrier
还差。 Here's一个简短的,可编辑的例子。有关如何改进它的任何建议吗?
答案 0 :(得分:3)
如果你有更多的处理器然后运行线程,那么在这里忙碌等待只会'更快'。如果你继续使用Thread.interrupted并且只是消耗CPU时间,那么实际上会显着降低性能。
CyclicBarrier / CountDownLatch出了什么问题?这似乎是一个更好的解决方案。
答案 1 :(得分:1)
这样的事情怎么样?这段代码有一个并发错误(如果一个线程在调用counter.get()
之间的速度很慢),但它应该可以解决,因为有两个计数器并重复这个代码两次,以便计数器交替。
if (counter.decrementAndGet() == 0) {
counter.set(numberOfThreads);
} else {
while (counter.get() < numberOfThreads) {}
}
请发布一个可以编译并演示性能问题的示例。否则所有答案都只是推测。
答案 2 :(得分:1)
很难想象繁忙等待循环会比非繁忙循环更快。首先,在您的代码中,使用CyclicBarrier时,您仍然需要使用同步(见下文)。其次,您刚刚重新实现了CyclicBarrier机制,Java开发人员花费时间和精力来优化它以获得最佳性能。第三,CyclicBarrier使用ReentrantLock进行同步,这显然比使用synchronized
关键字更有效,更快。总的来说,你的代码不太可能赢得比赛。
考虑这个参考代码:
public class MyRunnable implements Runnable {
private static CyclicBarrier barrier = new CyclicBarrier(threads.length);
public void run() {
// do work up to a "common point"
try{
barrier.await();
}catch(InterruptedException e){
Thread.interrupt();
//Something unlikely has happened. You might want to handle this.
}
}
}
在一次运行中,此代码将同步thread.length
次,这不会超过您的繁忙等待版本。因此它不能比你的代码慢。
性能问题的真正原因是你的线程在“遇到”之前几乎没有工作,这可能意味着存在高线程上下文切换开销以及大量同步。
你能重新考虑这个架构吗?你真的需要等待所有工人在共同点“见面”吗?你可以在他们的“会议”之前做更多的工作吗?您是否尝试将线程数设置为较小的数字(= CPU /核心数)?
您是否可以分享一些关于代码目的的更多信息并提供更多详细信息?
答案 3 :(得分:0)
等待/通知怎么办?
public class MyRunnable implements Runnable {
private static AtomicInteger counter = null; // initialized to the number
// of threads
public void run() {
// do work up to a "common point"
// need to synchronize for wait/notify.
synchronized ( counter ) {
// decrement the counter and - if necessary - reset it
if (counter.decrementAndGet() == 0) {
counter.set(numberOfThreads);
// notify all the waiting threads
counter.notifyAll();
}else{
// wait until all threads have reached the "common point"
counter.wait();
}
}
}
}
总的来说,如果你经常同步以至于屏障的开销是一个问题,那就很可疑:要么你做的工作不值得多线程,要么你的同步频率比你应该更频繁。