是否对类进行锁定,也会锁定类变量? - java

时间:2013-09-25 07:03:34

标签: java

我有以下课程

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方法中所做的那样),它是否也会锁定类成员/变量?请帮我解答。

5 个答案:

答案 0 :(得分:6)

  

对类进行锁定是否也会锁定类变量? - java

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

  

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

如果该方法中的代码在迭代期间修改了列表。但是,如果该类中的所有代码同步,,您还没有将该列表的引用添加到外部类的任何内容,然后你知道该方法中的代码正在运行。

但是,你可能会更好,同步列表本身。这样,即使您已经给出了对列表的引用,假设所有使用它的代码都在其上进行同步,那么您将不会遇到并发mod:

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.synchronizedList返回的列表或java.util.concurrent package中的内容。

答案 1 :(得分:1)

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

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

答案 2 :(得分: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将获取该对象的锁定。因为它不允许在你的类中同时调用另一个 synchronized方法或同步(this)块,如果有的话

答案 3 :(得分:0)

ArrayList会在集合上同时修改或在集合结构发生变化时进行迭代时抛出ConcurrentModificationException

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

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

答案 4 :(得分:0)

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

  

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