异常
++++ exception thrown while trying to get object from cache for key: s2i1-E%2573gyod66%2B1%25%25al%25%25yDue%25ila4xQp3ns%25irrloPteLvPsel372D3lu_2D%2B_af675c67093ec75db15b6d740733bd87_775183877_1837512; host:10.4.37.175:11241 -- null
java.nio.channels.ClosedByInterruptException
at java.nio.channels.spi.AbstractInterruptibleChannel.end(AbstractInterruptibleChannel.java:184)
at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:272)
at sun.nio.ch.SocketAdaptor$SocketInputStream.read(SocketAdaptor.java:195)
at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:86)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:258)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at java.io.DataInputStream.read(DataInputStream.java:132)
at com.ycache.danga.MemCached.SockIOPool$SockIO.readLine(SockIOPool.java:2023)
at com.ycache.danga.MemCached.MemCachedClient.get(MemCachedClient.java:1565)
at com.ycache.danga.MemCached.MemCachedClient.get(MemCachedClient.java:1489)
原因:
调用方使用了 Thread. Interrupt 方法 或者 Future.cancel方法。
解决办法:
1. 调用ycache的线程中,去掉Future.cancel 或者 Thread. Interrupt 方法使用
2. 通过抛出异常的方法
过程分析
当调用方使用ycache的MemCachedClient.get方法时,就会调用SocketChannelImpl.read 方法,在读取运行 begin方法,执行后使用 end方法
public int read(ByteBuffer dst) throws IOException { try { begin(); bytesRead = in.read(buf, 0, bytesToRead); } finally { end(bytesRead > 0); } if (bytesRead < 0) break; else totalRead += bytesRead; dst.put(buf, 0, bytesRead); } if ((bytesRead < 0) && (totalRead == 0)) return -1; return totalRead; } }
begin()会创建Interruptible 的interruptor 对象,同时将此对象赋值给了当前 Thread的 blocker对象 interruptor = new Interruptible() {
public void interrupt() {
synchronized (closeLock) {
if (!open)
return;
interrupted = true;
open = false;
try {
AbstractInterruptibleChannel.this.implCloseChannel(); // 关掉ChanelSocket
} catch (IOException x) { }
}
}};当 in.read 在执行且尚未执行完,此时调用方代码 执行了Thread. Interrupt 或者 Future.cancel 时,就会调用当前线程的blocker的interrupt方法,将interrupted 设置为true,同时关掉socket
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0();// Just to set the interrupt flag
b.interrupt();
return;
}
}
interrupt0();
}
- end(false),当没有读取到数据或者读取超时时,就会发生ClosedByInterruptException,代码如下
protected final void end(boolean completed)
throws AsynchronousCloseException
{
blockedOn(null);
if (completed) {
interrupted = false;
return;
}
if (interrupted) throw new ClosedByInterruptException();
if (!open) throw new AsynchronousCloseException();
}