java中的线程安全InputStream

时间:2014-06-23 05:40:25

标签: java multithreading inputstream

如何创建一个线程安全的InputStream。在多线程操作中,inputStream数据被破坏,所以我如何使我的inputStream线程安全。将使用以下代码

public class SynchronizedInputStream  extends InputStream{

    private InputStream in;

    private SynchronizedInputStream( InputStream in ) {
        this.in = in;
    }

    /* ... method for every InputStream type to use */
    public  static InputStream createInputStream( InputStream in) {
        return new SynchronizedInputStream( in);
    }

    public static InputStream createPushBackInputStream(InputStream in,int BUFSIZE){
        return new SynchronizedInputStream(new PushbackInputStream(in,BUFSIZE));
    }

    /* Wrap all InputStream methods Used */

    public int read(){
        synchronized (this) {
            try {
                return in.read();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return 0;
    }

    @Override
    public int available() {
        synchronized( this ) {
            try {
                return in.available();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return 0;
    }


}

在NANOHTTPD文件中

 public HTTPSession(TempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream, InetAddress inetAddress) {
            this.inputStream=(PushbackInputStream) SynchronizedInputStream.createPushBackInputStream(inputStream);
        /*lines of code..........*/
        }

然后我称之为

String Data = readStream(session.getInputStream());//session is HTTPSession
/*.....code....*/
private String readStream(InputStream in) {
        synchronized (in) {
            PushbackInputStream inputStream = (PushbackInputStream) in;
            StringBuffer outputBuffer = null;
            try {
                                 //Reading the InputStream Here
                }
            } catch (IOException ioe) {
                //error msg
            }
                return outputBuffer.toString();

        } 
    }

2 个答案:

答案 0 :(得分:9)

你需要考虑它是如何有意义的。想象一下,不止一个人正在读一本魔法书,它会在人们第一次看到它时删除这个角色。所以只有一个人可以阅读任何给定的角色。这就是流的方式。

这使得以有用的方式阅读本书变得非常困难。当最天真地完成时,每个人都会得到一些随机的角色子集;不是很有用的信息。

一个直接的解决方案是让一个人阅读它,然后将其复制到一本书上,当一个人读取它时,它不会删除字符。这样每个人都可以阅读这本书。在某些情况下,你并不需要每个人都能理解这本书,只要给他们一个句子,人们就可以工作。在这种情况下,一个读者可以将每个句子发布到一个队列中,每个人一次只能拿一个句子。

其他方法包括使用缓冲区,其中每个线程存储它们读取的字符,然后每次检查它们是否可以形成一个单词,如果是这样,则为下游处理发出单词。有关示例,请参阅Netty的编解码器包(例如this)。

然而,这些方法通常在流而不是在流内部实现。你可能有一个在里面做这些的流,但它可能会让人迷惑。

答案 1 :(得分:5)

简短的回答是,您向我们展示的类是线程安全的,但使用您的类的代码可能不是线程安全的!

你实现的是以原子方式读取一个字符的操作,并以原子方式测试是否有要读取的内容。这些操作的实现是线程安全的,如果(并且仅当)所有线程使用相同的SynchronizedInputStream对象来访问给定的InputStream,除了包装器之外没有任何东西访问InputStream直接

然而,这很可能是因为这不足以使您的应用程序在更广泛的意义上使用流线程安全。

我预计你所观察到的“腐败”实际上正在发生更高的层次;例如同时对read调用读取(说)消息的两个线程进行交错,以便消息的某些字节进入错误的线程。假设这是你的问题,那么这并没有解决它。您的read方法仅在线程读取单个字节时锁定流。解锁后,没有什么可以阻止不同的线程读取下一个字节。

有几种方法可以解决这个问题。例如“

  • 一种简单的方法是重构代码,只有一个> 从给定的InputStream读取。该线程读取消息,并将它们转换为可以通过队列传递给其他人的对象......例如。

  • 另一种方法是用一个以原子方式读取整个消息的包装类替换你的包装类。不要延长InputStream。而是根据较大规模的操作设计API,并在该粒度级别进行同步。

<强>更新

重新添加您添加的额外代码。

看起来像只有一个线程(当前请求线程)应该从输入流中读取。如果您只使用一个线程,那么应该没有多线程或线程安全问题。 (此外,这就是nanoHTTPD代码的工作方式。)

如果所有线程都是使用相同的synchronized (in) {对象。

问题在于,您的被攻击的readStream类正在为每个“会话”创建单独的in,这就是您的代码同步的内容。因此,如果(不知何故)两个线程使用相同的套接字输入流创建HttpSession个对象,它们将在不同的对象上同步,并且不会互斥。

但这都是猜想。到目前为止,您还没有证明有多个线程试图使用相同的输入流。