Java客户端锁定错误

Java客户端锁定错误,java,multithreading,Java,Multithreading,我试图理解客户端锁定 我的印象是,如果我们像下面的代码那样执行synchronized(elements){},整个列表将被锁定,并且在线程退出监视器之前不会进行添加或删除。但是我可以在addListElement方法中添加元素,并且在线程“thread-0”java.util.ConcurrentModificationException中获得异常 客户端锁定在java中是如何工作的 public class ClientLocking { public static void ma

我试图理解客户端锁定

我的印象是,如果我们像下面的代码那样执行
synchronized(elements){}
,整个列表将被锁定,并且在线程退出监视器之前不会进行添加或删除。但是我可以在
addListElement
方法中添加元素,并且在线程“thread-0”java.util.ConcurrentModificationException中获得
异常

客户端锁定在java中是如何工作的

public class ClientLocking {

    public static void main(String args[]) {
        System.out.println("Hello World!!");
        ClientLocking c = new ClientLocking();
        c.startProcess();
    }

    private final List<String> elements = new ArrayList<String>();

    private void startProcess() {

        addListElement("e1");
        addListElement("e2");
        addListElement("e3");

        MyThread t = new MyThread();
        t.start();

        addListElement("e4");
        addListElement("e5");
        addListElement("e6");

    }

    private void addListElement(String element) {

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        if (elements.add(element)) {
            System.out.println("Added : " + element);
        } else {
            System.err.println("Not Added : " + element);
        }
    }

    private class MyThread extends Thread {
        @Override
        public void run() {
            try {

                synchronized (elements) {
                    Iterator<String> it = elements.iterator();
                    while (it.hasNext()) {
                        String el = it.next();
                        System.out.println("Printing : " + el);
                        Thread.sleep(500); // Some processing
                    }
                }

            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
公共类ClientLocking{
公共静态void main(字符串参数[]){
System.out.println(“你好世界!!”;
ClientLocking c=新ClientLocking();
c、 startProcess();
}
私有最终列表元素=新的ArrayList();
私有void startProcess(){
添加列表元素(“e1”);
添加列表元素(“e2”);
addListElement(“e3”);
MyThread t=新的MyThread();
t、 start();
addListElement(“e4”);
addListElement(“e5”);
addListElement(“e6”);
}
私有void addListElement(字符串元素){
试一试{
睡眠(100);
}捕捉(中断异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
如果(元素。添加(元素)){
System.out.println(“添加:“+元素”);
}否则{
System.err.println(“未添加:+元素”);
}
}
私有类MyThread扩展线程{
@凌驾
公开募捐{
试一试{
已同步(元素){
迭代器it=elements.Iterator();
while(it.hasNext()){
字符串el=it.next();
系统输出打印项次(“打印:+el);
Thread.sleep(500);//一些处理
}
}
}捕捉(中断异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
}
}

只有当所有相关代码(所有“关键部分”)都在使用锁时,同步才起作用

在您的示例中,run使用
同步(元素)
,但addListElement不使用。因此,它不关心您的锁定方案


同步块当前所做的只是防止两个线程同时运行“run”(对于同一个列表)。您希望了解锁的任何其他代码也必须包括同步块(具有相同的监视器对象)。

只有当所有相关代码(所有“关键部分”)都使用锁时,同步才起作用

在您的示例中,run使用
同步(元素)
,但addListElement不使用。因此,它不关心您的锁定方案


同步块当前所做的只是防止两个线程同时运行“run”(对于同一个列表)。要知道锁的任何其他代码也必须包括同步块(使用相同的监视器对象)。

您还没有同步addElement方法本身

即使线程持有元素的监视器,add方法也不会尝试获取监视器

有两种方法。首先,将整个add方法标记为synchronized(这在没有监视器对象的情况下工作) 所以一次只允许一个线程调用add方法。但这不是你想要达到的

一个解决方案是,addMethod本身将尝试获取监视器。因此,在加法的主体周围放置另一块同步(元素)


但是您必须考虑,两个线程实际上使用相同的监视器对象

您尚未同步addElement方法本身

即使线程持有元素的监视器,add方法也不会尝试获取监视器

有两种方法。首先,将整个add方法标记为synchronized(这在没有监视器对象的情况下工作) 所以一次只允许一个线程调用add方法。但这不是你想要达到的

一个解决方案是,addMethod本身将尝试获取监视器。因此,在加法的主体周围放置另一块同步(元素)


但是您必须考虑,两个线程实际上使用相同的监视器对象

阅读《实践中的Java并发》一书。不,它没有。您必须(尝试)获得相同的锁,或者使用线程安全列表(如
CopyOnWriteArrayList
)。您必须(尝试)获得相同的锁,或者使用线程安全列表(如
CopyOnWriteArrayList
)。