Java-实现忙等待机制

Java-实现忙等待机制,java,multithreading,Java,Multithreading,在我的项目中,到目前为止,我已经使用一个线程“同步”了多个线程(每个线程运行相同类型的Runnable)。在我的例子中,由于同步的频率很高,使用循环载波器的效率很低,但是繁忙等待机制可能工作得更快。以下是我到目前为止得到的信息(遗漏了一些部分): 公共类MyRunnable实现Runnable{ 私有静态AtomicInteger计数器=null;//初始化为数字 //线程数 公开募捐{ //做到“共同点” 已同步(此){ //减小计数器,如有必要,将其复位 if(counter.decreme

在我的项目中,到目前为止,我已经使用一个线程“同步”了多个线程(每个线程运行相同类型的
Runnable
)。在我的例子中,由于同步的频率很高,使用
循环载波器
的效率很低,但是繁忙等待机制可能工作得更快。以下是我到目前为止得到的信息(遗漏了一些部分):

公共类MyRunnable实现Runnable{
私有静态AtomicInteger计数器=null;//初始化为数字
//线程数
公开募捐{
//做到“共同点”
已同步(此){
//减小计数器,如有必要,将其复位
if(counter.decrementAndGet()==0){
计数器设置(线程数);
//使所有忙碌等待的线程退出循环
对于(int i=0;i

不幸的是,此代码的性能甚至比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"

        // 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();
            }
        }
    }
}

一般来说,如果您经常进行同步,以致于屏障的开销成为一个问题,那么这是可疑的:要么您正在做不值得多线程处理的工作,要么您正在进行的同步频率比您应该做的要高。

忙在这里等待只会“更快”,如果您有更多的处理器,那么您就有线程在运行。如果您继续在Thread.interrupted上旋转,并且只消耗CPU时间,那么实际上会显著降低性能


自行车载货车/倒计时锁出了什么问题?这似乎是一个更好的解决方案。

像这样的解决方案怎么样?此代码有一个并发错误(如果在调用
counter.get()
)之间有一个线程运行缓慢),但应该通过使用两个计数器并重复此代码两次来解决,以便计数器交替运行

if (counter.decrementAndGet() == 0) {
    counter.set(numberOfThreads);
} else {
    while (counter.get() < numberOfThreads) {}
}
if(counter.decrementAndGet()==0){
计数器设置(线程数);
}否则{
while(counter.get()

请发布一个可以编译并演示性能问题的示例。否则,所有答案都只是猜测。

很难想象忙等待循环会比不忙等待循环快。首先,在您的代码中,您仍然使用了使用CyclicBarrier时所需的同步(见下文)。其次,您刚刚重新实现了CyclicBarrier机制,Java开发人员花时间和精力对其进行优化以获得最佳性能。第三,CyclicBarrier使用同步,这显然比使用
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/核心数)


你能分享更多关于代码目的的信息并提供更多细节吗?

这些问题似乎是代码审查的最佳选择(),你试着在那里问过了?如果你使用AtomicInteger并在线程对象itslef上同步,为什么需要同步块?@Asaf:既然你提到了,没有真正的理由这么做。但是,如果没有
synchronized
,它也会变慢。请发布一个SSCCE:线程在同步点之间做的工作相对较少,因此
CyclicBarrier
的开销降低了一切。(请参阅讨论)您的实现缺少计数器上的同步,因此抛出
IllegalMonitorStateException
s。除非您持有对象的监视器,否则无法调用
notifyAll()
wait()
。@ryyst:已修复。我通常不直接使用
wait()
notify[All]()
,所以我不确定锁应该如何工作。看。问题是由于与正在执行的同步数量相比,工作负载非常小。该代码的问题是它没有做任何工作。JVM优化了计算,所以剩下的就是同步。首先要理解这一点:尽管基准测试有缺陷,但我的代码使用两个计数器时速度要快2-16倍(取决于线程的数量;我在C2Q6600上测试了1-4个线程)。但是,如果线程数更多,则性能更差。这是意料之中的,因为同步总是会导致一些开销。下面是一个示例,它执行一些实际工作(调用Math.sqrt)并将其分布到多个线程上,以便线性扩展:作为旁注。与synchronized相比,Reentrantlock不会更快。Java6也是如此
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.
        }   
    }
 }