Java 我怎样才能访问此列表,同时又是线程安全的?
我的main生成了两个线程,它们都需要访问相同的列表。我不知道最好的方法是什么。这是我所拥有的,但我仍然遇到concurrentModificationExceptionJava 我怎样才能访问此列表,同时又是线程安全的?,java,multithreading,list,collections,Java,Multithreading,List,Collections,我的main生成了两个线程,它们都需要访问相同的列表。我不知道最好的方法是什么。这是我所拥有的,但我仍然遇到concurrentModificationException class Parent { private List<String> data; public List<String> getData() { return data; } public static void main(String args[]) {
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();
}
}
}
}
类父类{
私人名单数据;
公共列表getData(){
返回数据;
}
公共静态void main(字符串参数[]){
父级p=新父级();
p、 start();
}
公开作废开始(){
线程a=新线程(新线程a(此)).start();
线程b=新线程(新线程b(此)).start();
}
公共A实现可运行{
私人家长;
公共A(家长p){
父母=p;
}
公开募捐{
while(true){
parent.getData().add(“数据”);
}
}
}
公共B实现可运行{
私人家长;
公共B(家长p){
父母=p;
}
公开募捐{
迭代器i=parent.getData().Iterator();
while(i.hasNext()){
//和我一起做更多的事情
i、 删除();
}
}
}
}
我的
A
类基本上是数据的生产者,B
是消费者。我接受这样一种可能性,那就是我走错了方向。所以欢迎所有的帮助。我只需要能够安全地从一个线程添加到列表中,并从另一个线程中删除列表中的项目。提前感谢。好吧,对于制作人/消费者,我推荐或。这将处理并发读写(在本例中为推送/轮询)
您可能希望您的消费者运行,直到向其发送某种关机条件。如果您使用的是阻塞队列,这意味着您将要发送一个队列项目,指示消费者应停止消费。这将是一个关闭的阻塞队列实现
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
}
}
}
}
请注意,对于阻塞队列的轮询
结果没有空检查。这是因为,根据定义,阻塞队列会阻塞正在运行的线程,直到有东西存在
如果您希望消费者不与生产者发生冲突,那么您将需要定期轮询并休眠消费者线程。以下是使用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*/);
}
}
}
}
嗯,对于制作人/消费者,我推荐or。这将处理并发读写(在本例中为推送/轮询) 您可能希望您的消费者运行,直到向其发送某种关机条件。如果您使用的是阻塞队列,这意味着您将要发送一个队列项目,指示消费者应停止消费。这将是一个关闭的阻塞队列实现
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
}
}
}
}
请注意,对于阻塞队列的轮询
结果没有空检查。这是因为,根据定义,阻塞队列会阻塞正在运行的线程,直到有东西存在
如果您希望消费者不与生产者发生冲突,那么您将需要定期轮询并休眠消费者线程。以下是使用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*/);
}
}
}
}
影响最小的更改可能是使用同步的setter。
这样,线程必须等待锁释放后才能添加到集合。影响最小的更改可能是使用同步的setter。
这样,线程必须等待锁释放后才能添加到集合。不要使用列表代替队列。软件包中有大量用于生产者/消费者操作的实用程序。您可能需要的是阻止队列,而不是列表。酷,我会研究这些。如果我换掉列表,理论上它的其余部分可以吗?不要用列表代替队列。软件包中有大量用于生产者/消费者操作的实用程序。您可能需要的是阻止队列,而不是列表。酷,我会研究这些。如果我换掉这个列表,理论上它的其余部分可以吗?不要使用Thread.sleep()来做这个。相反,通过设置volatile标志并中断使用者线程,或者在队列中放置“毒丸”,来关闭队列。否则,答案很好。请随意改进答案:)。“毒丸”方法肯定能很好地处理阻塞队列。ConcurrentLinkedQueue的优点是它在生产者和消费者之间没有争用,这是底层算法的一个非常酷的特性。因此线程轮询可能需要一些CPU,但生产者永远不会被消费者锁定。我将研究这个“毒丸”,我需要尽可能避免睡觉。我已经更新了第一个使用毒丸的示例。好的,我喜欢这个,它比我以前想的更简单、更好。Thx的帮助@ChillDon't使用Thread.sleep()进行此操作。相反,通过设置volatile标志并中断使用者线程,或者在队列中放置“毒丸”,来关闭队列。否则,答案很好。请随意改进答案:)。“毒丸”方法肯定能很好地处理阻塞队列。ConcurrentLinkedQueue的优点是它在生产者和消费者之间没有争用,这是底层算法的一个非常酷的特性。因此线程轮询可能需要一些CPU,但生产者永远不会被消费者锁定。我将研究这个“毒丸”,我需要尽可能避免睡觉。我已经更新了第一个使用毒丸的示例。好的,我喜欢这个,它比我以前想的更简单、更好。谢谢你的帮助@Chill