当前位置: 代码迷 >> J2SE >> Hashtable 多线程遍历删除的奇怪有关问题!
  详细解决方案

Hashtable 多线程遍历删除的奇怪有关问题!

热度:722   发布时间:2016-04-24 00:29:21.0
Hashtable 多线程遍历删除的奇怪问题!!
项目中需要将一些对象存放到Hashtable中,当满足一定条件,再移除。同时还会有一个定时器定时检查Hashtable中的值,如果长时间无操作,也会移除Hashtable。
下面是代码模拟:
Java code
public class TT {        public static void main(String[] args) {        //模拟3200次        for(int y=0;y<3200;y++){                        Hashtable<Integer, String> hts = new Hashtable<Integer, String>();            for(int i=0;i<300;i++){                hts.put(i, "value="+i);            }            new Thread(new TestThread2(hts)).start();            new Thread(new TestThread(hts)).start();        }    }}

#TestThread
Java code
public class TestThread implements Runnable {    private Hashtable<Integer, String> hts;    public TestThread(Hashtable<Integer, String> hts) {        this.hts = hts;    }    @Override    public void run() {        //移除        hts.remove(1);    }}

#TestThread2

Java code
public class TestThread2 implements Runnable {    private Hashtable<Integer, String> hts;    public TestThread2(Hashtable<Integer, String> hts) {        this.hts = hts;    }    @Override    public void run() {        // 遍历                        //方法1        Iterator<Integer> it = hts.keySet().iterator();        while(it.hasNext()){            int k= it.next();    //此处抛 ConcurrentModificationException            System.out.println(k);        }                //方法2//        Enumeration<Integer> e = hts.keys();//        while (e.hasMoreElements()) {//            int key = e.nextElement();    //多次测试此处不会抛异常//            System.out.println(key+"--"+hts.get(key));//        }    }}


1、遍历的时候使用方法2为何不会抛异常?查看JDK文档说Iterator接口不是替换Enumeration的吗?
2、Hashtable不是线程安全的吗,为何方法1还会有ConcurrentModificationException异常??

还请各位高手解答……

------解决方案--------------------
ConcurrentModificationException是因为你用迭代器的同时 还在外部用了remove 这是不允许的 你的remove操作也要在迭代器里完成
尝试用一下CopyOnWriteArrayList 不过它的Iterator迭代出的值只是Iterator创建的 和后来修改无关.........
------解决方案--------------------
Iterator的next方法里面会调用 checkForComodification()判断集合是否被修改过,如果修改过就抛出ConcurrentModificationException异常。所以你的程序虽然是在其他地方remove,却是在next处抛异常。这个和是否是线程安全的没关系,是迭代器不允许。

Enumeration的nextElement方法没有进行“集合是否被修改”的检测,所以没有抛出异常。


------解决方案--------------------
Hashtable 中的迭代器不是线程安全的

建议使用 ConcurrentHashMap 这个是真正意义上的线程安全,包括迭代器

另外,如果你想实现 LRU 算法的 Map 的话,推荐使用继承 LinkedHashMap 重写 removeEldestEntry 方法就可以了。
  相关解决方案