我想为3个线程之间的通信创建一个静态arrayList: 1.线程会将一些数据添加到列表中; 2.线程将从列表中删除数据; 3.线程(每3秒一次计时器)将检查列表大小是否等于0,如果没有打印该列表的所有对象。
我很想知道如果超过1个线程会同时尝试访问此列表会发生什么(例如,当第二个线程将从列表中删除对象时,计时器将同时检查列表的大小)。 我想我必须同步这个列表,但不知道该怎么做。你能给我一些建议吗?
答案 0 :(得分:3)
我很想知道如果超过1个线程会尝试会发生什么 同时访问此列表
首先ArrayList
不是线程安全的 ,因此您不应直接使用它。
一种可能性是使用Collections.synchronizedList(...);
为您提供线程安全但会妨碍并发。
您的要求似乎与Queue
类似,因此您应该使用BlockingQueue
,例如线程安全的LinkedBlockingQueue
。
注意:强>
如果您使用Collections.synchronizedList(...)
,则列表中的复合操作仍然不安全。
答案 1 :(得分:2)
您可以使用
List myList = Collections.synchronizedList(new ArrayList());
答案 2 :(得分:2)
ArrayList
不是线程安全的。您需要自己处理同步,否则结果将无法预测。
根据相关问题的建议:How do I make my arraylist thread safe您可以使用Collections.synchronizedList(...)
获取List
的线程安全版
javadoc给出了一个如何利用该方法返回的List
的示例。
List list = Collections.synchronizedList(new ArrayList());
...
synchronized (list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
其他解决方案已经提出了这一点,但使用此方法可能会降低性能,因为同步会阻止对List
的并发访问。这最终将限制您添加&的速度。从支持List
中删除数据。
答案 3 :(得分:1)
此代码段将帮助您找到正确的方向
//have a lock Object
private static final Object lock = new Object();
// your list
private static List list = null
//synchronized on lock object. this will allow only one thread at a time
synchronized(lock){
//access,add to, remove from list
}
通过这种方式,您可以确保一次只有一个线程访问您的列表
答案 4 :(得分:1)
更好的是,使用并发原语(等待,通知和同步),您可以让打印线程等待,并且只有在其他一个线程实际更改了ArrayList之后才会唤醒。这样做的好处是,当没有变化时不打印,并且在发生变化时立即被唤醒。你可能仍会得到错误的唤醒,但如果这是一个问题,可以编码。
在打印线程中:
synchronized(lock)
{
while(true/*or some boolean to indicate you're done*/)
{
lock.wait();
//print list
}
}
在编辑列表的线程中:
synchronized(lock)
{
//modify list
lock.notify();
}
即使没有发生任何变化,您也可以在3秒后进行lock.wait(3000);
打印。