ayush
ayush

Reputation: 14568

java share data between thread

i have a java process that reads data from a socket server. Thus i have a BufferedReader and a PrintWriter object corresponding to that socket.

Now in the same java process i have a multithreaded java server that accepts client connections. I want to achieve a functionality where all these clients that i accept can read data from the BufferedReader object that i mentioned above.(so that they can multiplex the data)

How do i make these individual client threads read the data from BuffereReader single object? Sorry for the confusion.

Upvotes: 4

Views: 7020

Answers (3)

Enno Shioji
Enno Shioji

Reputation: 26882

In case you can't hold all the data in memory, you can use something like this: (Uses a classic observer pattern where one thread monitors the source and the others are notified of the new data)

class Broadcaster {
    private final ConcurrentSkipListSet<Listener> listeners =
         new ConcurrentSkipListSet<Listener>();

    private final BufferedReader source = //inject source

    // register / de-gegister code
    public void register(Listener listener);
    public void deRegister(Listener listener);
    // usually it's used like broadcaster.register(this);

    public void broadcast(){
        String read = null;
        while((read = source.readLine())!=null){
            for(Listener listener : listeners){
                listener.send(read);
            }
        }
    }
 }

and

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);
        }
    }
}

I didn't test this thing or anything, so have mercy if it doesn't work!

EDIT: If you have memory constraint, you might want to do this as well:

Queue<String> queue = new LinkedBlockingQueue<String>(2000);

This will put a upper limit on how many elements can queue up in the queue, and when this limit is reached, threads that want to put elements on it will have to wait (if add is used, that is). This way the Broadcaster will block (wait) when the listeners can't consume the data fast enough (while in this simple scheme other listener could starve).

EDIT2: When you do this, you should preferably put only immutable things on the Queue. If you put for example byte[], a impolite listener may change the data and the other threads may be surprised. If this is somehow impossible, you should put a different copy on each queue, e.g. byteArray.clone(). This may incur some performance hit though.

Upvotes: 1

rlibby
rlibby

Reputation: 6021

The easiest thing is probably to create a temporary file and use java.nio.channels.FileChannel. The reason is that this already provides the reader/writer semantics you want. An alternative is to re-implement these semantics yourself with an in-memory scheme.

What you would do is read from your reader and append to the end of the file. Then your readers would get file channels initially pointing to the end of the file. You'll have to be careful to make sure they don't think they have reached end of stream when you are simply waiting on more input from the reader. You can either make downstream logic aware of this or provide some kind of wrapper around the readers.

Edit: this was written with the understanding that you want all readers to see everything. This is too complicated if that's not in fact what you want.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500675

I would strongly suggest that they don't access the BufferedReader directly. Assuming you know the format of the data, and that each client is trying to read the same format (if that's not the case, I can't see how it could work at all) I would suggest creating one thread to read from the BufferedReader and put work items in a Queue. There are lots of example of using producer/consumer queues in Java, and this is also likely to make it easier to test the client code.

Having only one thread accessing the BufferedReader means you don't need to worry about defining an atomic operation that all other threads will have to content for - your reading thread effectively defines that operation by deciding to add a work item to the queue.

EDIT: If all the clients should see all of the data, that reinforces my suggestion of having a single reader even further - except instead of having a Queue of data which items are removed from, you'd have a collection which clients can read all the existing data from. You'll need to use an appropriately thread-safe collection, but there are plenty of those in Java.

EDIT: Having just read your comment which says that each client should just see the last item read from the reader, that makes it even easier. Have one thread reading the data, but just keep a single variable with a reference to "the last item read". You probably either want to synchronize access to it or use an AtomicReference, but both of those are easy.

Upvotes: 6

Related Questions