Java 带有LinkedBlockingQueue挂起的InputStream的自定义实现

Java 带有LinkedBlockingQueue挂起的InputStream的自定义实现,java,multithreading,stream,Java,Multithreading,Stream,我尝试实现一个InputStream,可以将字符串块传递给它。 从技术上讲,它应该可以工作,因为我所需要做的就是阻止InputStream#read()方法,仅此而已。或者我是这么想的。。。 以下是我对StringInputStream的自定义实现: public class StringInputStream extends InputStream { private LinkedBlockingQueue<Integer> buffer = new LinkedBlock

我尝试实现一个InputStream,可以将字符串块传递给它。
从技术上讲,它应该可以工作,因为我所需要做的就是阻止InputStream#read()方法,仅此而已。或者我是这么想的。。。 以下是我对StringInputStream的自定义实现:

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;
    }
}
公共类StringInputStream扩展了InputStream{
私有LinkedBlockingQueue缓冲区=新LinkedBlockingQueue();
公共void supplyData(字符串s){
for(char ch:s.toCharArray()){
buffer.add((int)ch);
}
}
@凌驾
public int read()引发IOException{
试一试{
返回buffer.take();
}捕捉(中断异常e){
e、 printStackTrace();
}
返回-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");
    }
}
公共类StreamsMain{
公共静态void main(字符串[]args)引发InterruptedException{
InputStream is=new ByteArrayInputStream(“eu ma duc la scoala\n sa ma distrez\nsi imi place la MAXIM!”.getBytes(StandardCharsets.utf8));
扫描仪scanner1=新扫描仪(is);
AtomicReference inputStream=新的AtomicReference(新的StringInputStream());
线程th=新线程(()->{
Scanner Scanner=新扫描仪(inputStream.get());
while(scanner.hasNextLine()){
System.out.println(“2.+scanner.nextLine());
}
});
th.start();
while(scanner1.hasNextLine()){
String line=scanner1.nextLine();
inputStream.get().supplyData(行+“\n”);
System.out.println(“1.”行);
}
System.out.println(“\n\n等待3秒从主线程退出”);
时间单位。秒。睡眠(3);
//th.中断();
System.out.println(“退出的主线程”);
}
}
在我的示例中,我从第一个inputstream读取数据,将这些行提供给我的自定义实现,然后在另一个线程中从我的自定义实现读取数据

奇怪的是: 除非我取消对th.interrupt()行的编译,否则我看不到任何输出,这只发生在主线程的休眠中(这没有意义,因为我正在另一个线程中读取我的StringInputStream)

你能帮我找出这个问题吗


亲切的问候,

实际上我自己也对这个很好奇,所以我开始查找这个

当我试着

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");
除了
read()
,因为您正在扩展一个接口。但是,扫描仪不会调用读取。您可以尝试这个类,看看它是否有效

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;
    }
}
如果从
读取(byte[]b,int off,int len)返回0个字节,则类将从
scanner.hasNextLine()返回false
。我猜你每天都会学到新东西


希望这有帮助

找到代码阻塞的地方——即使在主线程上运行,您确定您的StringInputStream实现了吗?我应该只实现read方法。我还尝试实现了其他的read方法,并使所有方法同步,但就像这样,它有时有效,有时无效。但我需要连续获取字符串块。另外,如果没有数据,read方法不是必须阻塞,而不是返回0吗?如果需要连续获取字符串块,则应该更新StringInputStream类的构造函数和内部变量以满足需要。当您返回0时,
scanner.hasNextLine()
返回false,您应该终止。你试过运行上面的代码吗?让我们看看。仅供参考:
InputStream
用于读取字节。
读取器
用于读取字符或字符串。你真的不应该混淆两者。我敢打赌
扫描器
使用缓冲I/O,你推送的全部内容都小于这个缓冲区大小。因此,当您不再推送任何内容时,它会挂起等待更多的传入数据。由于在中断时返回
-1
,也称为文件结束,因此它结束了等待。正确的解决方案是将某种文件结束标记推送到使用线程可以读取的流中。
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;
    }
}