1

I'm trying to implement a Multithreaded Server in Java where the server spawns a new thread for each client that connects to it. The communication is carried out in a class which implements the Runnable interface and takes the Socket descriptor as the input. When a new client connects, I spawn a new thread with the Socket descriptor number.

I need to maintain two ArrayLists at the server which are updated whenever a new client joins the system (with some data that the client sends). How can I accomplish this behaviour of sharing an ArrayList among multiple clients running in different threads?

3
  • A static Vector might be what you are looking for. Commented Nov 22, 2013 at 19:37
  • 1
    @JustinKSU sure, if you want to shoot yourself in your feet :) Commented Nov 22, 2013 at 19:41
  • 2
    Something from java.util.concurrent would be better. Commented Nov 22, 2013 at 19:45

3 Answers 3

1

You can create one instance of a concurrent collection in your main server thread, then pass it via a constructor to each of your Runnable socket handlers. (It sounds like you are already doing something like this to pass the Socket itself.)

CopyOnWriteArrayList is a concurrent List implementation, but it's not especially efficient. There are other collection types that support concurrent access, and might provide better performance.

Sign up to request clarification or add additional context in comments.

Comments

0

If you expect a lot of clients and want to access them randomly, use a ConcurrentSkipListMap. This gives you a highly efficient, thread-safe, non-blocking Map. Use the index numbers as keys, or use something more meaningful. If you just need a simple list (no random access) use a ConcurrentLinkedQueue, which is much the same thing except its a singly-linked list instead of a Map.

Another approach would be to use an ArrayList (or array, for that matter) but treat it as immutable. When you need to add a client, copy the old one, add the client to that, then swap the new one for the old one. (CopyOnWriteArrayList, as suggested by erickson, does this for you.) This will cost you when maintaining the list, but lets swarms of threads get hold of and use the list all at once. Admittedly, this technique only becomes really useful when you need to process the list after each add, maybe sorting it, and adding and removing a few entries affected by the add.)

Comments

0

If you want the ArrayLists to store per-client info and access it by client ID, I suggest just using a java.util.concurrent.ConcurrentHashMap with the client ID as key, as that is very straightforward to implement.

If you really need an ArrayList, I would hide it as an implementation detail in the server code. Then you would call some server methods from your Runnables to update the ArrayList. In this way you can start with something very simple like:

public class Server {
    ...      
    private ArrayList<Info> infos = new ArrayList<Info>();
    ...
    // Create one method for each *abstract* operation
    // that you need to perform on the ArrayList
    // (Do *NOT* implement read / write primitives
    // unless that is exactly what you need. The idea is
    // that all synchronization that you might need on 
    // the ArrayList happens inside those methods, so
    // the Runnables are unaware of the implementation
    // you haven chosen.)

    // Here I have used example operations that are
    // a bit more complex than read / write primitives
    // so the intention is more clear.

    public void clearInfo(int pos) {
        synchronized (infos) {
            infos.set(pos, null);
        }
    }

    public Info updateInfo(int pos, Info info) {
        Info oldInfo = null;
        synchronized (infos) {
            oldInfo = infos.get(pos);
            infos.set(pos, info);
        }
        return oldInfo;
    }
    ...
    public Info readInfo(int pos) {
        Info info = null;
        synchronized (infos) {
            infos.get(pos);
            info.incrementReadCount();
        }
        return null;
    }
    ...
}
...
public class ClientRunnable implements Runnable {
    ...
    private Server server;
    ...
    @Override
    public void run() {
        ...
        Info info = // getInfo();
        int writePos = // getWritePos();
        Info old = server.updateInfo(writePos, info);
        ...
        int readPos = // getReadPos();            
        Info newInfo = server.readInfo(readPos);
        ...
    }
    ...
}

Then, when you profile your application, if you find contention in accesses to your list you can fine tune locking or even change your implementation to a lock-free one while minimizing impact in your code. Locking is quite fast in Java nowadays so in many cases this simple solution might be good enough.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.