My Java NIO Selector được thực hiện sử dụng select() nên khối cho đến khi bất kỳ những xảy ra:Java NIO Selector select() trả về 0 mặc dù các kênh truyền hình đã sẵn sàng
- một kênh đăng ký sẵn sàng
- nó là wakeup() ' ed
- thread bị gián đoạn
Từ đó, tôi đã thực hiện một vài giả thuyết về trường hợp select()
trả về 0:
- nó hẳn phải là lý do 2. hay 3.
- selectedKeys() nên trả về một sản phẩm nào
ResultSet
- Tôi không cần phải gọi
selectedKeys()
và có thể tiếp tục lặp vòng lặp kế tiếp, nơiselect()
sẽ được gọi một lần nữa
Tuy nhiên, tôi gặp phải các tình huống trong đó select()
trả về 0 mặc dù có kênh sẵn sàng. selectedKeys()
trả về một Set
với 1 SelectionKey
như mong đợi.
Thậm chí nhiều cuộc gọi tới select()
sẽ luôn trả về 0 cho đến khi kênh được xử lý và SelectionKey
đã bị xóa. Tình trạng này về cơ bản kết thúc trong một vòng lặp vô tận như select()
không chặn nhưng luôn luôn ngay lập tức quay trở lại 0.
đang Giản:
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);
}
}
Tại sao select()
return 0 mặc dù có một kênh sẵn sàng chưa? Cách đề xuất để giải quyết vấn đề này là gì?
EDIT:
Thay đổi này:
for (SelectionKey key : readyKeys) {
if (key.isValid() && key.isReadable()) {
// Take action...
}
readyKeys.remove(key);
}
này
for (SelectionKey key : readyKeys) {
readyKeys.remove(key);
if (key.isValid() && key.isReadable()) {
// Take action...
}
}
giải quyết vấn đề. Trong một số trường hợp, mã sẽ continue
vòng lặp for
trước khi nhập remove()
.
EDIT 2:
Tôi chỉ vừa mới biết rằng foreach vòng lặp của tôi trên các phím chọn thiết là xấu. foreach sử dụng trình lặp của tập hợp. Sửa đổi một bộ sưu tập trực tiếp (không thông qua các phương thức của trình vòng lặp) trong khi lặp lại nó có thể dẫn đến hành vi "tùy ý, không xác định".
Tập hợp khóa đã chọn có thể cung cấp trình lặp số không nhanh. Thiết bị lặp không hoạt động phát hiện các sửa đổi như vậy và ném ConcurrentModificationException vào lần lặp tiếp theo.Vì vậy, sửa đổi các thiết lập trong một foreach hoặc rủi ro hành vi không xác định hoặc có thể gây ra ngoại lệ - tùy thuộc vào việc thực hiện iterator.
Giải pháp: không sử dụng foreach. Sử dụng trình vòng lặp và xóa khóa qua iterator.remove().
Iterator<SelectionKey> iterator;
SelectionKey key;
while (true) {
// ...
iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
key = iterator.next();
iterator.remove();
// ...
}
}
Có thể nếu khóa đã sẵn sàng và không bị xóa? – riha