Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java与ArrayList的并发性(如何处理?)_Java_Design Patterns_Observer Pattern_Concurrentmodification - Fatal编程技术网

Java与ArrayList的并发性(如何处理?)

Java与ArrayList的并发性(如何处理?),java,design-patterns,observer-pattern,concurrentmodification,Java,Design Patterns,Observer Pattern,Concurrentmodification,确实,当您尝试在遍历arraylist时修改它时,会出现ConcurrentModificationException错误,是吗?但是,如果先删除要修改的元素,遍历列表,然后重新插入该元素,那么错误是如何持续的呢?我不明白逻辑是否是这样,为什么会抛出concurrentmodificationexception 整个程序使用观察者模式 该程序的目的是拥有多个文本框,当您键入其中一个文本框时,其他文本框将使用相同的文本进行更新 主题-界面 public interface Subject {

确实,当您尝试在遍历arraylist时修改它时,会出现ConcurrentModificationException错误,是吗?但是,如果先删除要修改的元素,遍历列表,然后重新插入该元素,那么错误是如何持续的呢?我不明白逻辑是否是这样,为什么会抛出concurrentmodificationexception

整个程序使用观察者模式


该程序的目的是拥有多个文本框,当您键入其中一个文本框时,其他文本框将使用相同的文本进行更新

主题-界面

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