java 线程间同步的ArrayList

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4108974/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 04:47:49  来源:igfitidea点击:

Synchronized ArrayList between Threads

javamultithreadingarraylist

提问by zamN

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

我在理解如何在 java 中的线程之间同步 ArrayList 时遇到了一些困难。目前我的代码看起来像:

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 synchronizedListbut I'm not very sure how that works and if it is applicable to my situation.

这个例子只是为了展示我在做什么,它并不意味着有意义嘿嘿。无论如何,我想看看是否有可能在两个线程之间同步我的 ArrayList 'l'。所以运行 f.addMessage("Hello!"); 和 q.addMessage("World!");,两个消息都可以被任一类读取。我知道我可以轻松地创建一个单独的类来处理 ArrayList 并将其传递给两个 Connect 类,但我想看看是否有替代方法。我知道使用synchronizedList但我不太确定它是如何工作的以及它是否适用于我的情况。

Thanks.

谢谢。

回答by John Vint

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

你最好用 Collections.synchronizedList 包装 List。

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

回答by Cameron Skinner

Yes, you can do that. The art is in making sure that you are very careful about synchronizing access to the list. SynchronizedListwill 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.

是的,你可以这样做。艺术在于确保您对同步访问列表非常小心。SynchronizedList会经常做的伎俩,但它可能不是你想要的。它只会同步单个方法调用,因此如果您想以原子方式检查并删除列表的头部,这是不合适的。在这种情况下,您需要自己管理同步。

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 bothitems 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 synchronizedListwill be sufficient.

在上面的例子中,“Hello”和“World”字符串是原子地添加的:在这两个项目都被添加并且主线程退出同步块之前,两个工作线程不能继续。这可能是也可能不是您想要的:如果您不需要这种级别的控制,也许synchronizedList就足够了。

EDIT: I'm guessing that your Connectthreads 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. synchronizedListis only good for the most basic of synchronization tasks so isn't really useful a lot of the time.

编辑:我猜你的Connect线程正在从列表中拉出新项目并将它们发送到 IRC 频道。这意味着您几乎肯定想要执行自己的同步和等待/通知逻辑,或者您可能想要查看 java.util.concurrent 包。那里有很多有用的类可以满足您的需求。synchronizedList仅适用于最基本的同步任务,因此很多时候并没有真正有用。

回答by Cameron Skinner

Consider a ConcurrentLinkedQueueinstead, perhaps.

或许可以考虑使用ConcurrentLinkedQueue

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.concurrentpackage.

取决于操作,但它是我在 Java 中“传递消息”的朋友(这看起来是提供的代码的用法)。我也喜欢 CopyOnWriteArrayList :-) 无论如何,使用提供的java.util.concurrent包。

Edit:SO question about ConcurrentLinkedQueuewith some ineresting information.

编辑:关于 ConcurrentLinkedQueue 的 SO 问题,其中包含一些有趣的信息。

回答by aioobe

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

让两个连接对象共享对 a 的引用Vector。它基本上是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:

来自 API 文档:

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.

从 Java 2 平台 v1.2 开始,该类经过改造以实现 List 接口,使其成为 Java Collections Framework 的成员。与新的集合实现不同,Vector 是同步的。

回答by Mark Peters

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).

同步列表是一个很好的方法。如果您愿意(例如 LinkedList 而不是 ArrayList),它还可以让您在以后的道路上轻松使用不同的具体列表类型。