जोशुआ ब्लोच का "प्रभावी जावा", आइटम 51 थ्रेड शेड्यूलर के आधार पर नहीं है और साथ ही चलने योग्य स्थिति में धागे को अनावश्यक रूप से नहीं रखता है। उद्धरित पाठ:जावा कंसुरेंसी जेडीके 1.6: व्यस्त इंतजार सिग्नलिंग से बेहतर है? प्रभावी जावा # 51
runnable थ्रेड की संख्या नीचे रखने के लिए मुख्य तकनीक प्रत्येक थ्रेड काम की एक छोटी राशि करते हैं और फिर कुछ हालत Object.wait या का उपयोग कर बीतने वाले कुछ समय के लिए उपयोग करने के लिए इंतजार करना है Thread.Sleep। थ्रेड को व्यस्त नहीं होना चाहिए-प्रतीक्षा करें, बार-बार डेटा संरचना की जांच करने के लिए प्रतीक्षा करें। प्रोग्राम को शेड्यूलर की अनियमितता के लिए कमजोर बनाने के अलावा, व्यस्त-प्रतीक्षा प्रोसेसर पर लोड को काफी बढ़ा सकती है, अन्य प्रक्रियाओं को उसी मशीन पर पूरा करने वाले उपयोगी काम की मात्रा को कम कर सकती है।
और फिर सिग्नल का सही उपयोग करके एक व्यस्त प्रतीक्षा के माइक्रोबेंमार्क को दिखाने के लिए चला जाता है। पुस्तक में, व्यस्त प्रतीक्षा 17 राउंड ट्रिप/एस करता है जबकि प्रतीक्षा/अधिसूचना संस्करण प्रति सेकेंड 23,000 राउंड ट्रिप करता है।
हालांकि, जब मैंने जेडीके 1.6 पर एक ही बेंचमार्क की कोशिश की, तो मैं सिर्फ विपरीत दिखता हूं - व्यस्त प्रतीक्षा 760 के राउंडट्रिप्स/सेकेंड करता है जबकि प्रतीक्षा/अधिसूचना संस्करण 53.3K राउंडट्रिप्स/एस है - यानी, प्रतीक्षा/सूचित करें ~ 1400 गुना तेज हो गया है, लेकिन ~ 13 गुना धीमा हो गया है?
मैं समझता हूं कि व्यस्त प्रतीक्षा अच्छी नहीं है और सिग्नलिंग अभी भी बेहतर है - सीपीयू उपयोग व्यस्त प्रतीक्षा संस्करण पर ~ 50% है जबकि यह प्रतीक्षा/अधिसूचना संस्करण पर ~ 30% पर रहता है - लेकिन क्या कुछ ऐसा है जो बताता है संख्याएँ?
यदि यह मदद करता है, तो मैं विन 7 x64 (कोर i5) पर जेडीके 1.6 (32 बिट) चला रहा हूं।
अद्यतन: नीचे स्रोत। व्यस्त कार्य बेंच चलाने के लिए, पिंगपोंगक्यूयू की बेस क्लास को BusyWorkQueue आयात java.util.LinkedList में बदलें; आयात 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();
}
}
मुझे लगता है कि यह है। बस कोशिश की। दूसरी कतार में आइटम को छोड़ने से पहले 1 एमएम नींद के साथ पेश किया गया, दोनों रन काफी समान होते हैं - लगभग 400 राउंडट्रिप्स/एस। जैसा कि अपेक्षित है, व्यस्त प्रतीक्षा सीपीयू के 3 गुना अधिक उपयोग करता है। धन्यवाद! – Raghu