Java与ArrayList的并发性(如何处理?)
确实,当您尝试在遍历arraylist时修改它时,会出现ConcurrentModificationException错误,是吗?但是,如果先删除要修改的元素,遍历列表,然后重新插入该元素,那么错误是如何持续的呢?我不明白逻辑是否是这样,为什么会抛出concurrentmodificationexception 整个程序使用观察者模式Java与ArrayList的并发性(如何处理?),java,design-patterns,observer-pattern,concurrentmodification,Java,Design Patterns,Observer Pattern,Concurrentmodification,确实,当您尝试在遍历arraylist时修改它时,会出现ConcurrentModificationException错误,是吗?但是,如果先删除要修改的元素,遍历列表,然后重新插入该元素,那么错误是如何持续的呢?我不明白逻辑是否是这样,为什么会抛出concurrentmodificationexception 整个程序使用观察者模式 该程序的目的是拥有多个文本框,当您键入其中一个文本框时,其他文本框将使用相同的文本进行更新 主题-界面 public interface Subject {
该程序的目的是拥有多个文本框,当您键入其中一个文本框时,其他文本框将使用相同的文本进行更新 主题-界面
public interface Subject {
public void attach(Observer o);
public void detach(Observer o);
public void notifyAllObservers();
}
主语mpl-实现主语
import java.util.*;
public class SubjectImpl implements Subject {
private List <Observer> observers;
public SubjectImpl(){
observers = new ArrayList<Observer>();
}
@Override
public void attach(Observer o) {
observers.add(o);
}
@Override
public void detach(Observer o) {
observers.remove(o);
}
@Override
public void notifyAllObservers() {
//Iterating code
for(Observer o: observers){
o.update();
}
}
}
编辑器-实现观察者
import java.awt.*
import java.io.*;
import javax.swing.*;
public class Editor extends JFrame implements DocumentListener, Observer {
private FileContentSubject reference;
private JScrollPane textAreaScrollPane;
private JTextArea textArea;
public Editor(FileContentSubject filecontentsubject) throws IOException {
super("Editor");
initComponents();
this.reference = filecontentsubject;
textArea.getDocument().addDocumentListener(reference);
textArea.getDocument().putProperty("ownerEditor", this);
}
private void initComponents(){
textArea = new JTextArea();
//set location, size, visible and defaultcloseoperation here
getContentPane().setLayout(new BorderLayout());
getContentPane().add(textArea, BorderLayout.CENTER);
}
@Override
public void update() {
textArea.setText(reference.getState()); //Call to update each text box
}
@Override
public void changedUpdate(DocumentEvent e) {
}
@Override
public void insertUpdate(DocumentEvent e) {
}
@Override
public void removeUpdate(DocumentEvent e) {
}
}
文件内容系统-在Observer中充当具体主题(只有一个)
因为没有关于代码的问题,我用带问号的句子来回答 确实,当发生以下情况时,会出现ConcurrentModificationException错误 在遍历arraylist时尝试修改它,是吗 对。 要引发ConcurrentModificationException,您需要修改列表上调用方法的列表,然后尝试继续迭代 但是,如果首先删除元素,错误如何仍然存在 您需要修改、迭代列表,然后插入 元素回来了?我不明白逻辑是这样的,为什么呢 抛出concurrentmodificationexception 当您使用List.iterator()创建迭代器时,您将使用List创建一个契约,您将使用刚才创建的迭代器对象对列表进行所有修改 如果您直接删除一个元素-List.remove()-您就违反了约定 如果您直接添加一个元素-List.add()-您就违反了合同 列表或列表迭代器不关心是否修改元素本身
希望,这将为您澄清一些事情。既然没有关于代码的问题,我将用带问号的句子回答 确实,当发生以下情况时,会出现ConcurrentModificationException错误 在遍历arraylist时尝试修改它,是吗 对。 要引发ConcurrentModificationException,您需要修改列表上调用方法的列表,然后尝试继续迭代 但是,如果首先删除元素,错误如何仍然存在 您需要修改、迭代列表,然后插入 元素回来了?我不明白逻辑是这样的,为什么呢 抛出concurrentmodificationexception 当您使用List.iterator()创建迭代器时,您将使用List创建一个契约,您将使用刚才创建的迭代器对象对列表进行所有修改 如果您直接删除一个元素-List.remove()-您就违反了约定 如果您直接添加一个元素-List.add()-您就违反了合同 列表或列表迭代器不关心是否修改元素本身
希望,这将为您澄清问题。我相信您的
ConcurrentModificationException只有在使用3个或更多编辑器时才会抛出,对吗?无论如何,让我来解释一下发生了什么
假设您有3个Editor
实例:“Editor1”、“Editor2”和“Editor3”
这是当您在“Editor1”中键入文本(或者,我如何称呼它,当您“开始事件链”)时发生的情况:
到目前为止,正常的行为,对吗?问题是当调用Editor2的update()
时,它会更改Editor2的textArea
,而FileContentSubject
也是textArea
的DocumentListener
(就像Editor1的textArea
一样)
这将触发一个新版本,从而创建一个新的“事件链”。在实践中,将发生以下情况(从头开始重复):
这是抛出ConcurrentModificationException
的点。但是,它到底在哪里,在代码上
实际上,它在SubjectImpl
(!):
有什么问题吗?
问题是:
- 请注意,在带有
//first notification
注释的行中,有一个调用notifyAllobserver()
- 目前所附观察员名单是(按此顺序)[Editor2,Editor3]
notifyAllobserver()
,调用时,将开始在该列表上迭代
- 迭代的第一步是调用
Editor2.update()
。
Editor2.update()
- 当这条链结束时,附加的观察者列表现在是[Editor3,Editor2]
(注意:订单已更改!)
- 当
notifyAllobserver()
尝试继续下一步的迭代时,它会注意到列表已更改,并且。。。砰<将抛出代码>ConcurrentModificationException
为什么??因为您无法更改已开始迭代的列表。(使用迭代器或“foreach”。)
解决方案:
可能有很多,但最简单的就是停止“事件链”。要做到这一点,只需将Editor
上的update()
更改为:
@Override
public void update() {
textArea.setText(reference.getState()); // Call to update each text box
}
致:
这是什么意思?这意味着当一个编辑器由于其他人的原因而改变自己而不是在其文本区域键入内容时,他将不再通知FileContentSubject
(DocumentListener
),他只会悄悄地改变
这将从一开始就阻止任何第二个事件链
希望我能解释这个问题!如果我能说得更清楚,请告诉我!干杯 我相信您的ConcurrentModificationException
只有在使用3个或更多编辑器时才会抛出,对吗?无论如何,让我们
import javax.swing.event.*;
import javax.swing.text.*;
public class FileContentSubject implements Subject, DocumentListener {
private String state; //Current, most recent copy of everything
public String getState() {
return this.state;
}
private SubjectImpl reference;
@Override
public void attach(Observer o) {
reference.attach(o);
}
@Override
public void detach(Observer o) {
reference.detach(o);
}
@Override
public void notifyAllObservers() {
reference.notifyAllObservers();
}
public FileContentSubject() {
reference = new SubjectImpl();
}
@Override
public void changedUpdate(DocumentEvent arg0) {
}
@Override
public void insertUpdate(DocumentEvent arg0) {
Document doc = (Document) arg0.getDocument();
try {
this.state = doc.getText(0, doc.getLength());
} catch (BadLocationException e) {
e.printStackTrace();
}
Editor e = (Editor) doc.getProperty("ownerEditor");
reference.detach(e);
notifyAllObservers();
reference.attach(e);
}
@Override
public void removeUpdate(DocumentEvent arg0) {
//same as insertUpdate(DocumentEvent arg0) ^^
}
}
User types on Editor1 // chain begins
FileContentSubject detaches editor: Editor1
FileContentSubject begin notifyAllObservers(): [Editor2, Editor3]
Editor2 receives update() to new state
User types on Editor1 // chain begins
FileContentSubject detaches editor: Editor1
FileContentSubject begin notifyAllObservers(): [Editor2, Editor3] // first notification
Editor2 receives update() to new state // another chain begins! (the 1st chain didn't end yet!)
FileContentSubject detaches editor: Editor2
FileContentSubject begin notifyAllObservers(): [Editor3]
Editor3 receives update() to new state // chain THREE!!
FileContentSubject detaches editor: Editor3
FileContentSubject begin notifyAllObservers(): [] // empty list... nobody to notify
FileContentSubject reattaches editor: Editor3
FileContentSubject ended notifyAllObservers(): [Editor3] // chain 3 over
FileContentSubject reattaches editor: Editor2
FileContentSubject ended notifyAllObservers(): [Editor3, Editor2] // chain 2 over
@Override
public void notifyAllObservers() {
for (Observer o : observers) {
o.update();
}
}
@Override
public void update() {
textArea.setText(reference.getState()); // Call to update each text box
}
@Override
public void update() {
textArea.getDocument().removeDocumentListener(reference);
textArea.setText(reference.getState()); // Call to update each text box
textArea.getDocument().addDocumentListener(reference);
}