线程之间的同步ArrayList

时间:2010-11-05 18:36:08

标签: java multithreading arraylist

我在理解如何在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);
    }

}

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

感谢。

5 个答案:

答案 0 :(得分:9)

最好用Collections.synchronizedList包装List。

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

答案 1 :(得分:6)

是的,你可以这样做。本文的目的是确保您在同步访问列表时非常小心。 SynchronizedList通常会做到这一点,但可能不是你想要的。它只会同步单个方法调用,因此如果您想要自动检查并删除列表的头部,则它是不合适的。在这种情况下,您需要自己管理同步。

例如:

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

希望你明白了。同步需要读取或写入列表的操作,并确保所涉及的所有线程(包括main)都小心访问。

在上面的示例中,“Hello”和“World”字符串以原子方式添加:在两个项都已添加且主线程退出synchronized块之前,工作者都无法继续。这可能是你想要的,也可能不是你想要的:如果你不需要这种控制水平,那么synchronizedList就足够了。

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

答案 2 :(得分:3)

或许考虑一个ConcurrentLinkedQueue

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

编辑: SO question about ConcurrentLinkedQueue,其中包含一些不太有用的信息。

答案 3 :(得分:0)

让两个连接对象共享对Vector的引用。它基本上是ArrayList的同步版本。

这样的事情:

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

来自API文档:

  

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

答案 4 :(得分:0)

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

相关问题