什么是快速,等待通知或忙于等待Java?

Sac*_*hin 5 java multithreading

我知道使用busy-wait不是一个好的编程习惯,最好尽可能使用同步对象(wait-notify).但是我想知道一个人是否准备好牺牲cpu周期,然后忙着等待更快或等待通知?

我假设wait-notify将涉及对同步对象的内部锁定,并且信号可能来自内核以唤醒线程,使得这种方法比忙碌等待慢得多,其中人们可以直接检查条件直到它是满意.只要满足此条件(例如,布尔值== true),线程就可以从繁忙的等待中退出.根据我的理解,我感到很忙 - 等待应该更快.

如果我的论点是错误的,如果其他人能分享他们的想法并纠正我,我将不胜感激.

T.J*_*der 10

实验表明,如果你等待并等待并通知(在我的硬件上,无论如何),你会更快地看到旗帜.(详情如下.)差异非常非常非常小,所以这只适用于非常罕见的应用程序.例如,股票交易应用程序,公司可以获得他们可以获得的任何优势(争取尽可能在交易所附近找到他们的服务器,以便从交易所获得微网改进等)可能会认为差异是值得的.我也可以想象一些科学应用.

在绝大多数应用程序中,差异实际上没有任何区别.

但是,CPU发生的事情当然是其中一个核心硬件:

hardpeg

在影响盒子上的其他进程和数据中心的功耗方面,这是不好的.

所以:只有在真正重要的情况下才极度不情愿地使用.


数据(非常小的样本,但代码如下):

Busy Wait:       10631  12350  15278
Wait and Notify: 87299 120964 107204
Delta:           76668 108614  91926

时间是纳秒.十亿分之一秒.上面的平均增量为92403ns(0.092402667毫秒,0.000092403秒).

BusyWait.java:

public class BusyWait {

    private static class Shared {
        public long setAt;
        public long seenAt;
        public volatile boolean flag = false;
    }

    public static void main(String[] args) {
        final Shared shared = new Shared();
        Thread notifier = new Thread(new Runnable() {
            public void run() {
                System.out.println("Running");
                try {
                    Thread.sleep(500);
                    System.out.println("Setting flag");
                    shared.setAt = System.nanoTime();
                    shared.flag = true;
                }
                catch (Exception e) {
                }
            }
        });
        notifier.start();
        while (!shared.flag) {
        }
        shared.seenAt = System.nanoTime();
        System.out.println("Delay between set and seen: " + (shared.seenAt - shared.setAt));
    }
}
Run Code Online (Sandbox Code Playgroud)

WaitAndNotify.java:

public class WaitAndNotify {

    private static class Shared {
        public long setAt;
        public long seenAt;
        public boolean flag = false;
    }

    public static void main(String[] args) {
        (new WaitAndNotify()).test();
    }
    private void test() {
        final Shared shared = new Shared();
        final WaitAndNotify instance = this;
        Thread notifier = new Thread(new Runnable() {
            public void run() {
                System.out.println("Running");
                try {
                    Thread.sleep(500);
                    System.out.println("Setting flag");
                    shared.setAt = System.nanoTime();
                    shared.flag = true;
                    synchronized (instance) {
                        instance.notify();
                    }
                }
                catch (Exception e) {
                }
            }
        });
        notifier.start();
        while (!shared.flag) {
            try {
                synchronized (this) {
                    wait();
                }
            }
            catch (InterruptedException ie) {
            }
        }
        shared.seenAt = System.nanoTime();
        System.out.println("Delay between set and seen: " + (shared.seenAt - shared.setAt));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • while 循环通常不应该在同步块内,而不是相反? (2认同)

Cla*_*diu 5

人们准备好在繁忙等待时牺牲 CPU 周期,因为它更快。繁忙等待是实时低延迟应用程序的示例。

有一个名为lmax Disruptor 的框架,是为伦敦证券交易所构建的,锁定策略之一是忙等待,这就是他们使用它的方式。

为了达到超快的速度,最好在通知锁时浪费 CPU 周期,而不是浪费时间。

你对所有其他事情都是正确的,如果你用谷歌搜索一下disruptor并阅读他们的论文,你会得到更多的澄清。关于高性能和低延迟,有太多话可说。

Mechanical Sympathy是一个值得一看的好博客。