5

我有以下课程

public class Example{

    public static List<String> list = new ArrayList<String>();

    public static void  addElement(String val){
        synchronized(list){
            list.add(val);
        }
    }

    public static synchronized void printElement(){
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            //print element
        }
    }
}

printElement方法中的iterator()调用会抛出ConcurrentModificationException吗?基本问题是如果获得类对象的锁定(如在 printElement 方法中所做的那样),它是否也会锁定类成员/变量?请帮我解答。

4

5 回答 5

6

锁定类是否也会锁定类变量?- 爪哇

您的锁在您的实例上,而不是您的班级。不,它只锁定实例。

printElement方法中的iterator()调用会抛出ConcurrentModificationException吗?

如果该方法中的代码在迭代期间修改了列表,它会。但是,如果您在该类中的所有代码同步,并且您没有将该列表引用到您的类之外的任何内容,那么您知道只有该方法中的代码在运行。

不过,在列表本身上同步可能会更好。这样,即使您已经给出了对列表的引用,假设所有使用它的代码都在其上同步,您将不会受到并发 mods 的影响:

public static void printElement(){
//            ^--- No `synchronized ` here unless you REALLY need it for other reasons

    synchronized (list) {
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            //print element
        }
    }
}

如果您要提供参考并且想要确定,请使用返回的列表Collections.synchronizedListjava.util.concurrentpackage中的某些内容。

于 2013-09-25T07:08:20.463 回答
1

不,同步方法不会锁定对象变量,同步方法只会锁定this.

您的代码不是线程安全的,因为您锁定了 addElement 和 printElement 上的不同对象。如果同时调用这两个方法,则在迭代列表时没有什么可以阻止插入的发生。

于 2013-09-25T07:09:34.063 回答
1
Will the iterator() call in the printElement method throw ConcurrentModificationException?

是的,如果两个线程同时调用 addElement 和 printElement。为避免 ConcurrentModificationException,您可以使用CopyOnWriteList

if the lock on class object is acquired(as done in printElement method), will it lock the class members/ variables too?

同步方法 printElement 将获取此对象的锁定。因此,如果有的话,它不会允许在您的类中同时调用另一个同步方法或同步(this)块。

于 2013-09-25T07:23:43.173 回答
0

ArrayListConcurrentModificationException 当对集合同时进行修改或在集合结构发生变化的情况下进行迭代时抛出。

您应该更好地锁定列表对象资源。如果 list 有 getter 方法可以在外部访问它,那么它可以从外部修改结构。

synchronized (list) {
    Iterator<String> it = list.iterator();
    while(it.hasNext()){
        //print element
    }
}
于 2013-09-25T07:06:19.693 回答
0

您从未调用过addElement方法,因此锁定对此代码片段没有影响。在迭代集合时,如果您在同一个集合中插入/删除元素,您将获得ConcurrentModificationException. 来自Javadoc

例如,通常不允许一个线程在另一个线程对其进行迭代时修改 Collection。一般来说,在这些情况下,迭代的结果是不确定的。如果检测到此行为,某些迭代器实现(包括 JRE 提供的所有通用集合实现的那些)可能会选择抛出此异常。这样做的迭代器被称为快速失败迭代器,因为它们快速而干净地失败,而不是在未来不确定的时间冒着任意的、非确定性的行为的风险。

于 2013-09-25T07:10:54.440 回答