我的主要产生2个线程,他们都需要访问相同的列表。我不确定最好的办法是什么。这是我的,但我仍然遇到concurrentModificationException。
class Parent {
private List<String> data;
public List<String> getData() {
return data;
}
public static void main(String args[]) {
Parent p = new Parent();
p.start();
}
public void start() {
Thread a = new Thread(new A(this)).start();
Thread b = new Thread(new B(this)).start();
}
public A implements Runnable {
private Parent parent;
public A(Parent p) {
parent = p;
}
public void run() {
while (true) {
parent.getData().add("data");
}
}
}
public B implements Runnable {
private Parent parent;
public B(Parent p) {
parent = p;
}
public void run() {
Iterator<String> i = parent.getData().iterator();
while(i.hasNext()) {
// do more stuff with i
i.remove();
}
}
}
}
我的A
类基本上是数据的生成者,B
是消费者。我接受这种错误方式的可能性。所以欢迎所有的帮助。我只需要能够安全地从一个线程添加到列表中,并从另一个线程中删除列表中的项目。提前谢谢。
答案 0 :(得分:4)
嗯,对于制作人/消费者,我建议LinkedBlockingQueue或ConcurrentLinkedQueue。这将处理并发读取和写入(或在这种情况下推送/轮询)。
您可能希望您的消费者运行,直到向其发送一些关闭条件。如果您使用阻塞队列,这意味着您将要发送一个排队的项目,指示消费者应该停止消费。这将是一个关闭的阻塞队列实现。
public enum QueueItemType {
CONSUMABLE,
SHUTDOWN
}
public class QueueItem {
public final QueueItemType type;
public final String payload;
public QueueItem(QueueItemType type, String payload) {
this.type = type;
this.payload = payload;
}
}
public class B implements Runnable {
private Parent parent;
public B(Parent p) {
parent = p;
}
public void run() {
while(true) {
QueueItem data = parent.getData().poll();
if (data.type == QueueItemType.SHUTDOWN) {
break;
} else {
// do more stuff with data.payload
}
}
}
}
请注意,阻塞队列的poll
结果没有空检查。这是因为,根据定义,阻塞队列阻塞正在运行的线程,直到存在某些东西。
如果您希望消费者不与生产者竞争,那么您需要定期轮询并睡眠消费者线程。以下是使用ConcurrentLinkedQueue的示例:
public class B implements Runnable {
private Parent parent;
public B(Parent p) {
parent = p;
}
public void run() {
while(parent.isStillRunning()) {
String data = parent.getData().poll();
if (data != null) {
// do more stuff with data
} else {
Thread.sleep(10 /*10 ms, but you can make this whatever poll interval you want*/);
}
}
}
}
答案 1 :(得分:0)
影响最小的变化可能是使用同步的setter。 这样一个线程就必须等待锁释放才能添加到Collection。