मेरे जावा NIO चयनकर्ता इनमें से किसी भी जब तक select() तो यह ब्लॉकों का उपयोग कर कार्यान्वित किया जाता है कर रहे हैं के होते हैं:जावा NIO चयनकर्ता का चयन करें() 0 देता है हालांकि चैनल तैयार
- एक पंजीकृत चैनल तैयार
- है यह wakeup() है ' एड
- धागा
इस से बाधित है, मैं मामले के बारे में कुछ मान्यताओं बनाया जहां select()
रिटर्न 0:
- यह कारण 2. या 3. गया है चाहिए
- selectedKeys() लौट जाना एक खाली
ResultSet
- मैं अगले पाश यात्रा जहां
select()
बुलाया जाएगा करने के लिए जारी रख सकते हैंselectedKeys()
कॉल करने के लिए की जरूरत नहीं है और फिर
हालांकि, मुझे ऐसी परिस्थितियों का सामना करना पड़ा जहां select()
लौटाया गया था हालांकि एक तैयार चैनल है। selectedKeys()
Set
को 1 SelectionKey
के साथ अपेक्षित के रूप में देता है।
select()
तक कई कॉल भी चैनल को संसाधित होने तक 0 लौटाएंगे और SelectionKey
हटा दिया गया था। इस स्थिति में मूल रूप से select()
के रूप में एक अंतहीन लूप ब्लॉक नहीं करता में समाप्त होता है, लेकिन हमेशा तुरन्त 0.
सरलीकृत कोड वापस:
Selector selector = Selector.open();
SocketChannel channel;
for (...) { // for each node
// Create and connect channels...
...
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ, someRelatedObject);
}
int ready;
Set<SelectionKey> readyKeys;
while (true) {
ready = selector.select();
readyKeys = selector.selectedKeys();
System.out.println("Ready channels: " + ready);
System.out.println("Selected channels: " + readyKeys.size());
if (ready == 0) {
continue;
}
for (SelectionKey key : readyKeys) {
if (key.isValid() && key.isReadable()) {
// Take action...
}
readyKeys.remove(key);
}
}
क्यों select()
वापसी 0 यद्यपि वहाँ एक तैयार चैनल है? इससे निपटने का सुझाया गया तरीका क्या है?
संपादित करें:
इस बदलना:
for (SelectionKey key : readyKeys) {
if (key.isValid() && key.isReadable()) {
// Take action...
}
readyKeys.remove(key);
}
इस
for (SelectionKey key : readyKeys) {
readyKeys.remove(key);
if (key.isValid() && key.isReadable()) {
// Take action...
}
}
को समस्या हल हो। कुछ मामलों में, कोड लूप remove()
कुंजी से पहले लूप होगा।
संपादित करें 2:
मैं अभी हाल ही में पता चला कि मेरी foreach समूह चुनने चाबियाँ पर पाश बुरा है। foreach सेट के इटरेटर का उपयोग करता है। एक संग्रह को सीधे संशोधित करना (इटरेटर के तरीकों के माध्यम से नहीं) जबकि इसे फिर से चालू करने के परिणामस्वरूप "मनमाने ढंग से, अनिश्चित" व्यवहार हो सकता है।
चयनित कुंजी सेट असफल-तेज इटरेटर प्रदान कर सकता है। विफल-तेज इटरेटर इस तरह के संशोधनों का पता लगाते हैं और अगले पुनरावृत्ति पर ConcurrentModificationException फेंक देते हैं।इसलिए फोरैच में सेट को संशोधित करना या तो अपर्याप्त व्यवहार को जोखिम देता है या अपवाद का कारण बन सकता है - इटरेटर कार्यान्वयन के आधार पर।
समाधान: foreach प्रयोग नहीं करते। इटरेटर का प्रयोग करें और iterator.remove() के माध्यम से कुंजी को हटा दें।
Iterator<SelectionKey> iterator;
SelectionKey key;
while (true) {
// ...
iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
key = iterator.next();
iterator.remove();
// ...
}
}
संभवतः यदि कोई कुंजी तैयार थी और हटाया नहीं गया था? – riha