开发者

Synchronized ArrayList between Threads

开发者 https://www.devze.com 2023-01-23 12:21 出处:网络
I\'m having a bit of difficulty understanding how tosynchronize ArrayList\'s between threads in java.Currently my code looks like:

I'm having a bit of difficulty understanding how to synchronize ArrayList's between threads in java. Currently my code looks like:

Public class Runner {

    public static void main(String argv[]) {   
       Connect f = new Connect(irc.freenode.net, 6667);
       Thread ft = new Thread(f);
       ft.start();
       Connect q = new Connect(irc.quakenet.org, 6667);
       Thread qt = new Thread(q);
       qt.start();
       MessageParser mp = new MessageParser(f);
       MessageParser mp = new MessageParser(q);
       f开发者_如何转开发.addMessage("Hello!");
       q.addMessage("World!");
    }

}

public class Connect {

    public List<String> l = new ArrayList<String>();

    public static void addMessage(String str) {
        l.add(str);
    }

}

The example is just to show what I'm doing, it isn't meant to make sense heh. Anyway I wanted to see if it was possible to have my ArrayList 'l' synched up between both threads. So that running f.addMessage("Hello!"); and q.addMessage("World!");, both messages will be readable by either class. I know I could just easily make a seperate class that handles the ArrayList and pass it to both Connect classes but I wanted to see if there was an alternate way. I know about using a synchronizedList but I'm not very sure how that works and if it is applicable to my situation.

Thanks.


You are better off wrapping the List with Collections.synchronizedList.

List<String> l = Collections.synchronizedList(new ArrayList<String>());


Yes, you can do that. The art is in making sure that you are very careful about synchronizing access to the list. SynchronizedList will often do the trick but it might not be exactly what you want. It will only synchronize individual method calls so it is not appropriate if you want to, say, atomically check for and remove the head of the list. In that case you need to manage synchronization yourself.

For example:

class Worker extends Thread {
    private List<String> l;
    public Worker(List<String> list) {
        this.l = list;
    }

    public void run() {
        try {
            while (true) {
                synchronized (l) {
                    if (!l.isEmpty()) {
                        String s = l.remove(0);
                        System.out.println(this + " processed " + s);
                    }
                    else {
                        l.wait(1000);
                    }
                }
            }
        }
        catch (InterruptedException e) {
        }
    }
}

class Main {
    public static void main(String[] args) {
        List<String> list = new LinkedList<String>();
        Worker w1 = new Worker(list);
        Worker w2 = new Worker(list);
        w1.start();
        w2.start();
        synchronized (list) {
            list.add("Hello");
            list.add("World");
        }
    }
}

Hopefully you get the idea. Synchronize on operations that need to read or write to the list and make sure that all threads involved (including main) are careful about access.

In the example above the "Hello" and "World" strings are added atomically: neither worker can proceed until both items have been added and the main thread exits the synchronized block. This may or may not be what you want: if you don't need this level of control the maybe synchronizedList will be sufficient.

EDIT: I'm guessing that your Connect threads are pulling new items out of the list and sending them to the IRC channels. This means you almost certainly want to do your own synchronization and wait/notify logic, or you may want to take a look at the java.util.concurrent package. There are a bunch of useful classes in there that could suit your needs. synchronizedList is only good for the most basic of synchronization tasks so isn't really useful a lot of the time.


Consider a ConcurrentLinkedQueue instead, perhaps.

Depends on the operations, but it's my friend for "passing messages" in Java (which looks to be the usage from the provided code). I also like CopyOnWriteArrayList :-) Anyway, use the provided java.util.concurrent package.

Edit: SO question about ConcurrentLinkedQueue with some ineresting information.


Let both connect-objects share a reference to a Vector. It's basically a synchronized version of ArrayList.

Something like this:

public class Runner {

    public static void main(String argv[]) {   

       List<String> l = new Vector<String>();

       Connect f = new Connect(irc.freenode.net, 6667, l);
       Thread ft = new Thread(f);
       ft.start();
       Connect q = new Connect(irc.quakenet.org, 6667, l);
       Thread qt = new Thread(q);
       qt.start();
       MessageParser mp = new MessageParser(f);
       MessageParser mp = new MessageParser(q);
       f.addMessage("Hello!");
       q.addMessage("World!");
    }

}

public class Connect {

    List<String> l;

    public class Connect(String host, int port, List<String> l) {
        this.l = l;
        // ...
    }

    public static void addMessage(String str) {
        l.add(str);
    }
}

From the API docs:

As of the Java 2 platform v1.2, this class was retrofitted to implement the List interface, making it a member of the Java Collections Framework. Unlike the new collection implementations, Vector is synchronized.


Synchronized list is a good way to go. It also makes it easy to use a different concrete list type later on down the road if you want to (e.g. LinkedList instead of an ArrayList).

0

精彩评论

暂无评论...
验证码 换一张
取 消