jasonsunsoa
jasonsunsoa
2013-02-13 23:59
浏览 595
已采纳

多线程 java.util.ConcurrentModificationException 问题

目标:定义一个Producer类创建Student并添加到studnts集合中,再定义一个Consumer类从studnts集合中取出数据并打印控制台。Producer,Consumer类都实现了Runnable接口。

在MainTest类的main方法中创建线程并启动,如下所示:

        Producer p = new Producer();
        Thread tp1 = new Thread(p);
        tp1.start();
       
        Consumer c = new Consumer();
        Thread tc1 = new Thread(c);
        tc1.start();

这个时候,当tc1线程要执行的时候就报java.util.ConcurrentModificationException错误,我本是对线程调用这一块儿不是太明白。请大侠们帮我解决一下儿,请告诉我问啥会出这样的问题。

 

具体类如下所示:

 

 

Student类:一个普通类,其中定义了一个name属性和一个age属性。

public class Student {
    private String name;
    private String age;
   
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
   
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((age == null) ? 0 : age.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (age == null) {
            if (other.age != null)
                return false;
        } else if (!age.equals(other.age))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

   
   
}

 

Classroom接口:其中定义了一个名称为studnts的List用于存放Student对象。

public interface Classroom {
    List<Student> studnts = new ArrayList<Student>();
}

 

State抽象类:其中定义了一个状态,想用这个对studnts集合的操作进行控制。

public abstract class State {
    boolean state=true;
}

 

Producer类:添加Student到studnts中。

public class Producer extends State implements Runnable, Classroom {
    private int i=0;
    @Override
    public void run() {
        while(true) {
           
            if(i<10) {
                saveStudent();
            }
        }       
    }
   
    public synchronized void saveStudent() {
       
        if(!state) {
            try {
                wait();
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
       
        Student s = new Student();
        s.setName("name"+i);
        s.setAge("age"+i++);
        studnts.add(s);
       
        System.out.println(Thread.currentThread().getName()+" --- Add Student "+s.getName()+" -- "+s.getAge());
       
        state=true;
        notify();
    }

}

Consumer类:从studnts中取出strut对象并打印出来。

public class Consumer extends State implements Runnable, Classroom {
   
    @Override
    public void run() {
        while(true) {
            getStudent();
        }
    }
   
    public synchronized void getStudent() {

        if(!state) {
            try {
                wait();
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }   
           
        for(Student s : studnts) {
            System.out.println(Thread.currentThread().getName()+" --- get Stduent "+s.getName()+" --- "+s.getAge());
        }
       
        state = false;
       
        notify();
   
    }

}

 

 

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • silentlakeside
    silentlakeside 2013-02-14 14:20
    已采纳

    Classroom里定义的students是静态的,因此会被Producer和Consumer共享。Producer和Consumer在各自的线程里同时访问students,但是又没有同步(这两个类里是在方法上加synchronized,即在类实例上做同步,Producer和Consumer是不同实例,因此他们是不同步的), 所以会造成ConcurrentModificationException。

    解决的方法是:不在方法上加synchronized,而是使用synchronized (students)同步块来同步Producer和Consumer里的操作。

    另外最好不要将students当作静态变量,这样让人不好理解,可以将students作为构造函数的参数传入producer和Consumer。

    点赞 评论

相关推荐