java在线程之间共享数据

java在线程之间共享数据,java,multithreading,thread-safety,client,Java,Multithreading,Thread Safety,Client,我有一个从套接字服务器读取数据的java进程。因此,我有一个与该套接字对应的BufferedReader和PrintWriter对象 现在在同一个java进程中,我有一个多线程java服务器,它接受客户端连接。我想实现一个功能,在这个功能中,我接受的所有客户机都可以从我上面提到的BufferedReader对象读取数据。(这样他们就可以多路传输数据) 如何使这些单独的客户端线程从BuffereReader单个对象读取数据?很抱歉造成混淆。我强烈建议它们不要直接访问BufferedReader。假

我有一个从套接字服务器读取数据的java进程。因此,我有一个与该套接字对应的
BufferedReader
PrintWriter
对象

现在在同一个java进程中,我有一个多线程java服务器,它接受客户端连接。我想实现一个功能,在这个功能中,我接受的所有客户机都可以从我上面提到的
BufferedReader
对象读取数据。(这样他们就可以多路传输数据)


如何使这些单独的客户端线程从BuffereReader单个对象读取数据?很抱歉造成混淆。

我强烈建议它们不要直接访问
BufferedReader
。假设您知道数据的格式,并且每个客户端都试图读取相同的格式(如果不是这样,我根本看不出它是如何工作的),我建议创建一个线程从
BufferedReader
读取,并将工作项放入
队列中。Java中有很多使用生产者/消费者队列的示例,这也可能使测试客户机代码变得更容易

只有一个线程访问
BufferedReader
意味着您不必担心定义一个原子操作,而所有其他线程都必须满足这个操作——您的读取线程通过决定向队列中添加一个工作项来有效地定义该操作

编辑:如果所有的客户端都应该看到所有的数据,这进一步加强了我的建议,即拥有一个单一的读卡器-除了没有一个
队列
,而是拥有一个客户端可以从中读取所有现有数据的集合。您需要使用适当的线程安全集合,但Java中有很多这样的集合


编辑:刚刚读了你的评论,上面说每个客户应该只看到从读者那里读到的最后一个项目,这使它变得更容易。让一个线程读取数据,但只保留一个引用“最后读取的项目”的变量。您可能想要同步对它的访问,或者使用
原子引用
,但两者都很简单。

最简单的事情可能是创建一个临时文件并使用
java.nio.channels.FileChannel
。原因是,这已经提供了所需的读写器语义。另一种方法是使用内存中的方案自己重新实现这些语义

您要做的是从读取器中读取并附加到文件的末尾。然后,您的读者将获得文件通道,最初指向文件的末尾。当您只是在等待来自阅读器的更多输入时,您必须小心确保他们不会认为他们已经到达了流的末尾。您可以让下游逻辑意识到这一点,或者在读取器周围提供某种包装


编辑:写这篇文章的目的是为了让所有读者都能看到一切。如果事实上这不是您想要的,那么这就太复杂了。

如果无法在内存中保存所有数据,您可以使用以下方法: (使用一个经典的观察者模式,其中一个线程监视源,其他线程收到新数据的通知)

class广播员{
私有最终ConcurrentSkipListSet侦听器=
新的ConcurrentSkipListSet();
private final BufferedReader source=//注入源
//注册/注销代码
公共无效寄存器(侦听器);
公共作废注销人(监听器);
//通常它像广播员一样使用;
公共广播{
字符串读取=null;
而((read=source.readLine())!=null){
for(侦听器:侦听器){
发送(读取);
}
}
}
}

类侦听器实现可运行{
private final Queue=new LinkedBlockingQueue();
公共无效发送(字符串读取){
添加(读取);
}
公开募捐{
而(!Thread.currentThread().isInterrupted()){
字符串get=queue.get();
System.out.println(got);
}
}
}
我没有测试过这个东西,所以如果它不起作用,请发发慈悲吧

编辑:如果您有内存限制,可能还需要执行以下操作:

Queue<String> queue = new LinkedBlockingQueue<String>(2000);
Queue Queue=newlinkedblockingqueue(2000);
这将对队列中可以排队的元素数量设置一个上限,当达到该上限时,希望将元素放入其中的线程将不得不等待(即,如果使用了
add
)。这样,当监听器不能足够快地使用数据时(在这个简单的方案中,其他监听器可能会饿死),广播者将阻塞(等待)


EDIT2:执行此操作时,最好只在队列中放置不可变的内容。例如,如果您输入
byte[]
,一个不礼貌的侦听器可能会更改数据,其他线程可能会感到惊讶。如果这在某种程度上是不可能的,您应该在每个队列上放置不同的副本,例如,
byteArray.clone()
。这可能会导致性能下降。

我假设您是说所有线程都应该获得所有数据,不仅仅是谁先读谁就应该得到一段特定的数据?他们所有人都应该得到数据,这是目前来自BufferedReader流的数据。@ayush:我认为你不理解johusman的问题-你是想在不同的客户机之间分割数据,还是所有人都应该看到所有的数据?如果数据是0,1,2,3,4,那么每个客户机应该看到0,1,2,3,4还是一个客户机看到0,1,3而另一个客户机看到2,4?@ayush,但是你看到了@johusman所做的区别吗?每个线程都需要读取所有数据吗?或者你希望每个线程只得到某些不相交的数据块。我希望所有线程都读取相同的数据。这是从
class Listener implements Runnable {
    private final Queue<String> queue = new LinkedBlockingQueue<String>();

    public void send(String read){
        queue.add(read);
    }

    public void run(){
        while(!Thread.currentThread().isInterrupted()){
            String got = queue.get();
            System.out.println(got);
        }
    }
}
Queue<String> queue = new LinkedBlockingQueue<String>(2000);