Java Concurrency JDK 1.6:忙碌等待比信令好吗?有效的Java#51

前端之家收集整理的这篇文章主要介绍了Java Concurrency JDK 1.6:忙碌等待比信令好吗?有效的Java#51前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
Joshua Bloch的“Effective Java”,第51项不是依赖于线程调度程序,也不是在可运行状态下不必要地保留线程.引用文字

The main technique for keeping the number of runnable threads down is to have each thread
do a small amount of work and then wait for some condition using Object.wait or for some
time to elapse using Thread.sleep. Threads should not busy-wait,repeatedly checking a data
structure waiting for something to happen. Besides making the program vulnerable to the
vagaries of the scheduler,busy-waiting can greatly increase the load on the processor,
reducing the amount of useful work that other processes can accomplish on the same machine.

然后继续显示忙碌等待的微基准测试与正确使用信号.在书中,忙碌等待执行17次往返/秒,而等待/通知版本每秒执行23,000次往返.

但是,当我在JDK 1.6上尝试相同的基准测试时,我看到恰恰相反 – 忙等待是760K往返/秒,而等待/通知版本是53.3K往返/秒 – 也就是说,等待/通知应该是~1400时间更快,但结果慢了约13倍?

我知道繁忙的等待并不好,信号仍然更好 – 忙等待版本的cpu利用率约为50%,而等待/通知版本的停留率约为30% – 但有没有解释数字的东西?

如果它有帮助,我在Win 7 x64(核心i5)上运行JDK1.6(32位).

更新:来源如下.要运行繁忙的工作台,请将PingPongQueue的基类更改为BusyWorkQueue
import java.util.LinkedList;
import java.util.List;

abstract class SignalWorkQueue { 
    private final List queue = new LinkedList(); 
    private boolean stopped = false; 

    protected SignalWorkQueue() { new WorkerThread().start(); } 

    public final void enqueue(Object workItem) { 
        synchronized (queue) { 
            queue.add(workItem); 
            queue.notify(); 
        } 
    } 

    public final void stop()  { 
        synchronized (queue) { 
            stopped = true; 
            queue.notify(); 
        } 
    } 
    protected abstract void processItem(Object workItem) 
        throws InterruptedException; 
    private class WorkerThread extends Thread { 
        public void run() { 
            while (true) {  // Main loop 
                Object workItem = null; 
                synchronized (queue) { 
                    try { 
                        while (queue.isEmpty() && !stopped) 
                            queue.wait(); 
                    } catch (InterruptedException e) { 
                        return; 
                    } 
                    if (stopped) 
                        return; 
                    workItem = queue.remove(0); 
                } 
                try { 
                    processItem(workItem); // No lock held 
                } catch (InterruptedException e) { 
                    return; 
                } 
            } 
        } 
    } 
}

// HORRIBLE PROGRAM - uses busy-wait instead of Object.wait! 
abstract class BusyWorkQueue {
    private final List queue = new LinkedList();
    private boolean stopped = false;

    protected BusyWorkQueue() {
        new WorkerThread().start();
    }

    public final void enqueue(Object workItem) {
        synchronized (queue) {
            queue.add(workItem);
        }
    }

    public final void stop() {
        synchronized (queue) {
            stopped = true;
        }
    }

    protected abstract void processItem(Object workItem)
            throws InterruptedException;

    private class WorkerThread extends Thread {
        public void run() {
            final Object QUEUE_IS_EMPTY = new Object();
            while (true) { // Main loop
                Object workItem = QUEUE_IS_EMPTY;
                synchronized (queue) {
                    if (stopped)
                        return;
                    if (!queue.isEmpty())
                        workItem = queue.remove(0);
                }

                if (workItem != QUEUE_IS_EMPTY) {
                    try {
                        processItem(workItem);
                    } catch (InterruptedException e) {
                        return;
                    }
                }
            }
        }
    }
}

class PingPongQueue extends SignalWorkQueue {
    volatile int count = 0;

    protected void processItem(final Object sender) {
        count++;
        SignalWorkQueue recipient = (SignalWorkQueue) sender;
        recipient.enqueue(this);
    }
}

public class WaitQueuePerf {
    public static void main(String[] args) {
        PingPongQueue q1 = new PingPongQueue();
        PingPongQueue q2 = new PingPongQueue();
        q1.enqueue(q2); // Kick-start the system

        // Give the system 10 seconds to warm up
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
        }

        // Measure the number of round trips in 10 seconds
        int count = q1.count;
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
        }
        System.out.println(q1.count - count);

        q1.stop();
        q2.stop();
    }
}

解决方法

在您的测试中,队列连续获取新项目,因此忙碌等待实际等待很少.

如果队列每1ms获得一个新项目,您可以看到忙等待将花费大部分时间来刻录cpu.它会减慢应用程序的其他部分.

所以这取决于.如果你忙着等待用户输入,那肯定是错的;而像AtomicInteger这样的无锁数据结构中的繁忙等待肯定是好的.

原文链接:https://www.f2er.com/java/120676.html

猜你在找的Java相关文章