2009-12-12 13 views
1

Lorsque je crée un canal de la InputStream avec Channels.newChannel (est) bibliothèque standard Java retourne un ReadableByteChannelImpl, qui est:comportement incohérent ReadableByteChannelImpl Java

private static class ReadableByteChannelImpl 
     extends AbstractInterruptibleChannel // Not really interruptible 
     implements ReadableByteChannel 
    { 
     InputStream in; 
     private static final int TRANSFER_SIZE = 8192; 
     private byte buf[] = new byte[0]; 
     private boolean open = true; 
     private Object readLock = new Object(); 

     ReadableByteChannelImpl(InputStream in) { 
      this.in = in; 
     } 

     public int read(ByteBuffer dst) throws IOException { 
      int len = dst.remaining(); 
      int totalRead = 0; 
      int bytesRead = 0; 
      synchronized (readLock) { 
       while (totalRead < len) { 
        int bytesToRead = Math.min((len - totalRead), 
               TRANSFER_SIZE); 
        if (buf.length < bytesToRead) 
         buf = new byte[bytesToRead]; 
        if ((totalRead > 0) && !(in.available() > 0)) 
         break; // block at most once 
        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; 
      } 
     } 

     protected void implCloseChannel() throws IOException { 
      in.close(); 
      open = false; 
     } 
    } 

Comme vous pouvez le voir des blocs lors de l'appel de lecture (ByteBuffer dst) pour la première fois, et ne bloque plus jamais. Voir:

  if ((totalRead > 0) && !(in.available() > 0)) 
       break; // block at most once 

Quelle est la raison derrière un tel comportement étrange?

En outre, quelle est la motivation pour étendre AbstractInterruptibleChannel sans réellement rendre ce canal vraiment interruptible?

Répondre

1

Il ne bloque pas si elle est déjà lu au moins un octetet le flux sous-jacent annonce qu'aucun octet sont available. Notez que InputStream#available() peut renvoyer zéro même lorsque certains octets sont disponibles, mais ne devrait pas promettre plus d'octets que peut être lu sans bloquer. Par conséquent, cela ReadableByteChannel fait un effort pour lire au moins un octet - en supposant que le ByteBuffer fourni a de la place pour au moins un octet - et, ayant fait, ne tentera pas de lire à nouveau le flux sous-jacent sauf si le flux promet plus Les octets sont disponibles sans blocage.

Quant à savoir pourquoi ReadableByteChannelImpl étend AbstractInterruptibleChannel, je soupçonne que ce soit pour faire en sorte que l'enveloppé InputStream sera fermé correctement à l'appel Channel#close(), dont le contrat est affiné par InterruptibleChannel#close(). L'extension AbstractInterruptibleChannel permet à ReadableByteChannelImpl d'emprunter ses protections d'état ouvertes et fermées.

Il s'agit d'un peu de publicité mensongère, comme vous le dites, n'étant pas vraiment interruptible, mais tolérant d'être fermé à partir d'un fil séparé, et rendant idessentiel.

+0

Yeap, je l'ai déjà moi-même. La principale raison du blocage pendant le premier appel read() est simplement l'absence de toute méthode fiable pour vérifier si le flux sous-jacent est vide sans le lire réellement. –