异常

++++ 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. 通过抛出异常的方法

过程分析

  1. 当调用方使用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;
        }
    }
    
  2. 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) { }
    }
    }};

  3. 当 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();
}
  1. 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();
    }
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐