2016-03-29 12 views
0

文字列を渡すことができるInputStreamを実装しようとしました。
技術的には、私がする必要があったのはInputStream#read()メソッドをブロックすることだけだったので、うまくいくはずです。LinkedBlockingQueueがハングするInputStreamのカスタム実装

public class StringInputStream extends InputStream { 
    private LinkedBlockingQueue<Integer> buffer = new LinkedBlockingQueue<>(); 

    public void supplyData(String s) { 
     for (char ch : s.toCharArray()) { 
      buffer.add((int) ch); 
     } 
    } 

    @Override 
    public int read() throws IOException { 
     try { 
      return buffer.take(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     return -1; 
    } 
} 

そして、ここではそれをテストするために私のコードです:

public class StreamsMain { 
    public static void main(String[] args) throws InterruptedException { 
     InputStream is = new ByteArrayInputStream("eu ma duc la scoala\n sa ma distrez\nsi imi place la MAXIM!".getBytes(StandardCharsets.UTF_8)); 
     Scanner scanner1 = new Scanner(is); 
     AtomicReference<StringInputStream> inputStream = new AtomicReference<>(new StringInputStream()); 
     Thread th = new Thread(() -> { 
      Scanner scanner = new Scanner(inputStream.get()); 
      while (scanner.hasNextLine()) { 
       System.out.println("2. " + scanner.nextLine()); 
      } 
     }); 
     th.start(); 

     while (scanner1.hasNextLine()) { 
      String line = scanner1.nextLine(); 
      inputStream.get().supplyData(line + "\n"); 
      System.out.println("1. " + line); 
     } 

     System.out.println("\n\nwaiting 3 seconds to exit from MAIN thread"); 
     TimeUnit.SECONDS.sleep(3); 
     //th.interrupt(); 
     System.out.println("exited MAIN thread"); 
    } 
} 

私の例では、私はから読んでいるか、私はそう...ここ はStringInputStreamの私のカスタム実装であると思いました最初のinputstream、私は私のカスタム実装にラインを供給し、私は別のスレッドで私のカスタム実装から読んでいます。

私はth.interrupt()行を分解しない限り、出力が表示されません。他のスレッドのStringInputStream)。

問題を見つけてもらえますか?

敬具、

+1

FYI: 'InputStream'は_bytes_を読み込むためのものです。 'Reader'は_characters_またはStringsを読み込むためのものです。あなたは本当に_二つを混ぜ合わせてはいけません。 –

+0

'Scanner'はバッファされたI/Oを使うと思います。プッシュする内容はすべてこのバッファサイズより小さくなります。そのため、何も入力していないときに、より多くの着信データを待っています。中断したときにファイルの終わりを-1と返すので、待機を終了します。正しい解決策は、消費スレッドが読むことができるストリームに何らかのファイル終わりマーカーをプッシュすることです。 – Holger

答えて

0

私は実際に私は、私がいることを意味し、印刷スキャナの初期化、前

Thread th = new Thread(() -> { 
    System.out.println("Before scanner initialization"); 
    Scanner scanner = new Scanner(inputStream.get()); 
    while (scanner.hasNextLine()) { 
     System.out.println("2. " + scanner.nextLine()); 
    } 
}); 
th.start(); 

印刷をしようとしたとき

をこれを探し始めた私自身、このの好奇心になりました新しいスキャナの初期化がスレッドをブロックしています。

私は実際にInputStreamクラスから継承しようとはしませんでしたが、メインスレッドでこれを実行しようとすると、初期化はブロックされませんでした。

ここ

実際のコードブロック

AtomicReference<StringInputStream> inputStream = new AtomicReference<>(new StringInputStream()); 
System.out.println("before"); 
Scanner scanner = new Scanner(inputStream.get()); 
while (scanner.hasNextLine()) { // Code is blocking here 
    System.out.println("2. " + scanner.nextLine()); 
} 
System.out.println("after"); 

だから、前後ではないのに対し、印刷されます。


は、私はあなたの正確な要件のかわからないけど、あなたのInputStreamとスキャナを使用したい場合は、あなたがするのでread()に加えて

read(byte[] b, int off, int len) 

をoverrridingする必要があります

をそれを考え出しましたあなたはインターフェイスを拡張しています。ただし、読み取りはスキャナから呼び出されません。このクラスを試して、それが機能するかどうかを調べることができます。あなたはread(byte[] b, int off, int len)から0バイトを返す場合

class StringInputStream extends InputStream { 

    byte[] bytes; 
    int index = 0; 

    public StringInputStream(byte[] bytes) { 
     this.bytes = bytes; 
    } 

    public int read() { 
     return bytes[index]; 
    } 


    public int read(byte[] b, int off, int len) { 
     if(index == bytes.length) 
      return 0; 
     b[0] = bytes[index++]; 
     return 1; 
    } 
} 

クラスはscanner.hasNextLine()からfalseを返します。あなたは毎日何か新しいことを学ぶと思います。

うまくいけば、これが役に立ちます。

+0

私は自分自身で、おかげで、調査を続けます:) – adragomir

+0

コードがブロックされている場所が見つかりました。メインスレッドで実行している場合でも、StringInputStreamを実装していますか? – jrhee17

+0

私はreadメソッドだけを実装することになっています。また、他のメソッドを実装してメソッドを読み込み、すべてのメソッドを同期させるようにしましたが、このように、時にはうまくいきません。 – adragomir

関連する問題