zoukankan      html  css  js  c++  java
  • LinkedList线程安全问题

    Java中LinkedList是线程不安全的,那么如果在多线程程序中有多个线程访问LinkedList的话会出现什么问题呢?

    抛出ConcurrentModificationException

    JDK代码里,ListItr的add(), next(), previous(), remove(), set()方法都会跑出ConcurrentModificationException。

    final void checkForComodification() { 
            if (modCount != expectedModCount) 
            throw new ConcurrentModificationException(); 
        }

    代码中,modCount记录了LinkedList结构被修改的次数。Iterator初始化时,expectedModCount=modCount。任何通过Iterator修改LinkedList结构的行为都会同时更新expectedModCount和modCount,使这两个值相等。通过LinkedList对象修改其结构的方法只更新modCount。所以假设有两个线程A和B。A通过Iterator遍历并修改LinkedList,而B,与此同时,通过对象修改其结构,那么Iterator的相关方法就会抛出异常。这是相对容易发现的由线程竞争造成的错误。

    通过LinkedList对象修改其结构

    如果两个线程都是通过LinkedList对象修改其结构,会发生什么呢?我们先看一下JDK中LinkedList的数据结构。

    这是一个双向循环链表。header的作用就是能快速定位链表的头和尾。图中,“n”表示next,“p”表示previous。header的n指向first element;p指向last element。当一个线程A调用LinkedList的addFirst方法时(假设添加节点“4”),它首先更新“4”的n和p,n->3, p->header。此为第一步。第二步,更新节点“3”和herder的n和p,3n不变, 3p->4, headern->4, headerp不变。假设两个线程A,B同时调用addFirst(4), addFirst(5),会发生什么呢?很可能4,5的n指向3,p都指向header。(这里不是很确定,没有写代码测试,貌似无法从LinkedList获得entry)。也可能addFirst后,紧接着发现getFirst已经不是刚刚加入的元素。

    package linkedlist;

    import java.util.Iterator; 
    import java.util.LinkedList; 
    import java.util.concurrent.Executors;

    public class Test {

        private final LinkedList<Integer> list = new LinkedList<Integer>();

        public Test() { 
            Thread add1 = new Thread(new Runnable() {

                @Override 
                public void run() { 
                    int number = 0; 
                    while (true) { 
                        if (number == 10) 
                            number = 0; 
                        // System.out.println("Writing " + number); 
                        list.addFirst(number); 
                        int first = list.getFirst(); 
                        if (first != number) { 
                            System.err.println("ERROR!!! " + number + " " + first); 
                            System.exit(-1); 
                        } 
                        number++; 
                        System.out.flush(); 
                        try { 
                            Thread.sleep(2); 
                        } catch (InterruptedException e) { 
                            // TODO Auto-generated catch block 
                            e.printStackTrace(); 
                        } 
                    } 
                } 
            });

            Thread add2 = new Thread(new Runnable() {

                @Override 
                public void run() { 
                    int number = 100; 
                    while (true) { 
                        if (number > 119) { 
                            number = 100; 
                        } 
                        // System.out.println("Writing " + letter); 
                        // System.out.flush(); 
                        list.addFirst(number); 
                        int first = list.getFirst(); 
                        if (first != number) { 
                            System.err.println("ERROR!!! " + number + " " + first); 
                            System.exit(-1); 
                        } 
                        number++; 
                        try { 
                            Thread.sleep(2); 
                        } catch (InterruptedException e) { 
                            // TODO Auto-generated catch block 
                            e.printStackTrace(); 
                        } 
                    } 
                } 
            });

            Executors.newCachedThreadPool().execute(add1); 
            Executors.newCachedThreadPool().execute(add2); 
            // Executors.newCachedThreadPool().execute(read2); 
        }

        /** 
         * @param args 
         */ 
        public static void main(String[] args) { 
            Test test = new Test(); 
        } 
    }

    程序输出:

    ERROR!!! 0 100

    总结一下,线程安全问题是由多个线程同时写或同时读写同一个资源造成的。这里只是通过分析LinkedList的相关源码浅显的分析,下一步就要考虑如何解决或避免线程竞争了。

    建议办法是:
    将LinkedList全部换成ConcurrentLinkedQueue试试,LinkedList是线程不安全的。
    有兴趣可以参考http://byline.ow2.org/ccm-core-6.1.0/api/com/arsdigita/developersupport/Comodifications.html

  • 相关阅读:
    计算机组成原理--中断系统
    操作系统--文件管理2
    操作系统--文件管理1
    操作系统--存储管理4
    操作系统--存储管理3
    操作系统--存储管理2
    操作系统--存储管理1
    有序线性表(存储结构数组)--Java实现
    【Java】之static静态方法与非static静态方法区别
    【Android Studio】之构建项目报错
  • 原文地址:https://www.cnblogs.com/balaamwe/p/2466658.html
Copyright © 2011-2022 走看看