精华内容
下载资源
问答
  • 多线程ArrayList 出现null的问题 发现这个问题 在某个项目中使用了ArrayList 了,将他带入到 子线程中去添加待定值,然后出现了意向不到的错误,报空指针异常,出现一个 null 值,而且该问题不必现,有时候经常跑代码才...

    多线程下 ArrayList 出现null的问题

    发现这个问题

    在某个项目中使用了ArrayList 了,将他带入到 子线程中去添加待定值,然后出现了意向不到的错误,报空指针异常,出现一个 null 值,而且该问题不必现,有时候经常跑代码才出现几次.

    排查

    • 反复查看代码,未发现明显可能会出现 null 的地方,返回的值(上文中的添加待定值)在其他方法中都不为null
    • 在代码中插入打印代码判断为null的情形,进行打印,加断点,分析,发现 在对添加待定值 进行为null 判断时不起作用,而 在对list 进行为null 判断时进入断点,
    • 结合这个反馈和代码的源码进行分析,感觉可能是ArrayList 的问题,这才突然想起来ArrayList 是线程不安全的,这才百度发现确实有这个问题
    • 代码进行验证
      在大插入下,运行 3-4 次就有一次会出现 null 的情况,证实了想法
      	// ArrayList 线程不安全, add 方法在多线程 环境下 会出现意外的 null 值
      @Test
      void testListThread() throws InterruptedException {
          ArrayList list = new ArrayList();
          CountDownLatch latch = new CountDownLatch(1000);
          for (int i = 0; i < 1000; i++) {
              new Thread(new Runnable() {
                  @Override
                  public void run() {
                      list.add("abc");
                      latch.countDown();
                  }
              }).start();
          }
      
          latch.await();
          if(list.contains(null)) {
              System.out.println("list 包含 null 值");
              int index = list.indexOf(null);
              System.out.println(index);
              System.out.println(list);
          }
      }
      

      反省

      对java 集合的源码阅读还是不够熟悉,有些知识明明之前看过,但还是习惯性的用哪些常用的线程不同步的类,在多线程下没用仔细思考选用的对象

    解决方案

    1. List list = Collections.synchronizedList(new ArrayList(...)); 使用 Collections.synchronizedList 去包裹要使用的集合
    2. CopyOnWriteArrayList(线程安全,但是可能会对内存占用较大,垃圾回收频繁)
    3. Vector (线程同步的集合对象,操作大数据的时候会比较慢)
    展开全文
  • 问题:在多线程中使用ArrayList调用Add()添加元素时,有时候会出现下面的错误Exception in thread "Thread-1" Exception in thread "Thread-2" java.lang.ArrayIndexOutOfBoundsException: 15 at java.util....

    问题:

    在多线程中使用ArrayList调用Add()添加元素时,有时候会出现下面的错误

    Exception in thread "Thread-1" Exception in thread "Thread-2" java.lang.ArrayIndexOutOfBoundsException: 15
        at java.util.ArrayList.elementData(ArrayList.java:418)
        at java.util.ArrayList.get(ArrayList.java:431)
        at com.jant.demo_jant.DemoJantApplication$AddToTest.run(DemoJantApplication.java:35)
        at java.lang.Thread.run(Thread.java:745)
    java.lang.ArrayIndexOutOfBoundsException: 15
        at java.util.ArrayList.add(ArrayList.java:459)
        at com.jant.demo_jant.DemoJantApplication$AddToTest.run(DemoJantApplication.java:32)
        at java.lang.Thread.run(Thread.java:745)

    那么问题来了,ArrayList是自动扩容、没有长度限制,为什么还会出现数组下标越界这种错误呢?

    示例代码:

    通过这个示例,来研究一下

    public class DemoJantApplication {
    
        public static List<Integer> numberlist = new ArrayList<>();
    
        class AddToTest implements Runnable {
    
            int startNum = 0;
    
            public AddToTest(int startNum) {
                this.startNum = startNum;
            }
    
            @Override
            public void run() {
                int count = 0;
                while (count < 100) {
    
                    try {
                        java.lang.Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    numberlist.add(startNum);
                    System.out.println(java.lang.Thread.currentThread().getName() + "--" + (count) + "times"
                            +" 被添加的数字:"+ startNum
                            + ",list的最后数字:" + numberlist.get(numberlist.size() - 1)
                            + ",集合的大小:" + numberlist.size()
                            + ",list" + numberlist.toString());
    
                    startNum += 2;
                    count++;
                }
            }
        }
    
        public static void main(String[] args) {
            Thread t = new Thread(new DemoJantApplication().new AddToTest(0));
            Thread t1 = new Thread(new DemoJantApplication().new AddToTest(100));
            t.start();
            t1.start();
        }
    }

    打印出的log,我把他分为三种情况:

    情况一:

    这种情况算是正常情况,因为元素没有丢失:

    线程1和线程2,第0次执行,但是集合的大小都是2

    Thread-1--0times 被添加的数字:0,list的最后数字:100,集合的大小:2,list[0, 100]
    Thread-2--0times 被添加的数字:100,list的最后数字:100,集合的大小:2,list[0, 100]
    Thread-1--1times 被添加的数字:2,list的最后数字:2,集合的大小:4,list[0, 100, 102, 2]
    Thread-2--1times 被添加的数字:102,list的最后数字:2,集合的大小:4,list[0, 100, 102, 2]
    Thread-1--2times 被添加的数字:4,list的最后数字:4,集合的大小:5,list[0, 100, 102, 2, 4]

    情况二:

    线程1和线程2,第0次执行,但是集合的大小都是1

    Thread-1--0times 被添加的数字:0,list的最后数字:100,集合的大小:1,list[100]
    Thread-2--0times 被添加的数字:100,list的最后数字:100,集合的大小:1,list[100]
    Thread-1--1times 被添加的数字:2,list的最后数字:2,集合的大小:2,list[100, 2]
    Thread-2--1times 被添加的数字:102,list的最后数字:102,集合的大小:3,list[100, 2, 102]
    Thread-1--2times 被添加的数字:4,list的最后数字:104,集合的大小:4,list[100, 2, 102, 104]

    情况三:

    添加元素出现错误

    Exception in thread "Thread-1" Exception in thread "Thread-2" java.lang.ArrayIndexOutOfBoundsException: 15
        at java.util.ArrayList.elementData(ArrayList.java:418)
        at java.util.ArrayList.get(ArrayList.java:431)
        at com.jant.demo_jant.DemoJantApplication$AddToTest.run(DemoJantApplication.java:35)
        at java.lang.Thread.run(Thread.java:745)
    java.lang.ArrayIndexOutOfBoundsException: 15
        at java.util.ArrayList.add(ArrayList.java:459)
        at com.jant.demo_jant.DemoJantApplication$AddToTest.run(DemoJantApplication.java:32)
        at java.lang.Thread.run(Thread.java:745)

    分析

    首先,ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。

    对于ArrayList而言,它实现List接口、底层使用数组保存所有元素。其操作基本上是对数组的操作。

    先来看下ArrayList 使用add() 添加元素的流程:

    1、添加元素,其中size是elementData数组中元组的个数,初始为0。

    public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }

    2、确定list的容量,其作用为保证数组的容量始终够用

    private void ensureCapacityInternal(int minCapacity) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                  //DEFAULT_CAPACITY 为10
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            }
    
            ensureExplicitCapacity(minCapacity);
        }
    
        private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
    
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }

    3、扩展list的长度,每次数组容量的增长大约是其原容量的1.5倍

    private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                newCapacity = hugeCapacity(minCapacity);
            // minCapacity is usually close to size, so this is a win:
            //拷贝数组,返回新长度的数组
            elementData = Arrays.copyOf(elementData, newCapacity);
        }

    数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中

    4、接下来回到Add()函数,继续执行,elementData[size++] = e;

    当添加一个元素的时候,它可能会有两步来完成:

    1. 如果需要增大 Size 的值。
    2. 在 elementData[Size] 的位置存放此元素;

    下面针对示例的三种情况逐一分析:

    在单线程运行的情况下,如果 Size = 0,添加一个元素后,此元素在位置 0,而且 Size=1;

    情况一:

    执行顺序,在多线程情况下

    线程 A 向ArrayList添加元素,位置0 。

    线程 B 向ArrayList添加元素,位置1

    线程A执行打印代码

    线程B执行打印代码

    情况二:

    如果是在多线程情况下,

    1、刚开始ArrayList 大小为0,首次扩充大小为10 (通过size获得的是实际存储数据的大小)
    2、线程 A 添加元素,此时size 为0。在准备执行elementData[0] = e; 之后执行size++时 CPU 调度线程A暂停
    3、线程B 添加元素,此时size 为0,执行了elementData[0] = e; 之后执行size++,此时size为1.
    4、此时线程A继续执行size++ ,此时size为1.

    所以线程B添加的值会被线程A添加的值覆盖

    情况三:

    观察发生越界时的数组下标,分别为10、15、22、33、49和73。
    结合前面讲的数组自动机制,数组初始长度为10,第一次扩容为15=10+10/2,第二次扩容22=15+15/2,第三次扩容33=22+22/2…以此类推,通过不断调试可以发现,越界异常都发生在数组扩容之时。

    1、 当集合中已经添加了14个元素时,线程A率先进入add()方法,在执行ensureCapacityInternal(size + 1)时,发现还可以添加一个元素,故数组没有扩容,但随后线程A被阻塞在此处。

    2、接着线程B进入add()方法,执行ensureCapacityInternal(size + 1),由于线程A并没有添加元素,故size依然为14,依然不需要扩容,所以该线程就开始添加元素,使得size++,变为15,数组已经满了。

    3、 此时线程A运行,开始执行elementData[size++] = e;,它要在集合中添加第16个元素,而数组容量只有15个,所以就发生了数组下标越界异常!


    参考:

    ArrayList在多线程调用Add()添加元素时的下标越界问题(java.lang.ArrayIndexOutOfBoundsException)

    这篇博客写的不错,但是下面这段话分析不正确:

    而如果是在多线程情况下,比如有两个线程,线程 A 先将元素存放在位置 0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此 ArrayList 添加元素,因为此时 Size 仍然等于 0 (注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加 Size 的值。那好,我们来看看 ArrayList 的情况,元素实际上只有一个,存放在位置 0,而 Size 却等于 2。这就是“线程不安全”了。这就解释了为何集合中会出现null。

    展开全文
  • 点击上方[全栈开发者社区]→右上角[...]→[设为星标⭐]ArrayList 不是线程安全的,这点很多人都知道,但是线程不安全的原因及表现,怎么在多线程情况下使用ArrayList,可能...

    点击上方[全栈开发者社区]右上角[...][设为星标⭐]

    ArrayList 不是线程安全的,这点很多人都知道,但是线程不安全的原因及表现,怎么在多线程情况下使用ArrayList,可能不是很清楚,这里总结一下。

    1. 源码分析

    查看 ArrayList 的 add 操作源码如下:

    /**
         * Appends the specified element to the end of this list.
         *
         * @param e element to be appended to this list
         * @return <tt>true</tt> (as specified by {@link Collection#add})
         */
        public boolean add(E e) {
          // 判断列表的capacity容量是否足够,是否需要扩容
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            // 将元素添加进列表的元素数组里面
          elementData[size++] = e;
            return true;
        }
    

    源码中涉及的几个元素及方法定义如下:

    /**
         * Default initial capacity.
         */
        private static final int DEFAULT_CAPACITY = 10;
        /**
        * 列表元素集合数组
         * 如果新建ArrayList对象时没有指定大小,那么会将EMPTY_ELEMENTDATA赋值给elementData,
         * 并在第一次添加元素时,将列表容量设置为DEFAULT_CAPACITY 
       */
        transient Object[] elementData; 
    
        /**
       *列表大小,elementData中存储的元素个数
       */
        private int size;
    
       private void ensureCapacityInternal(int minCapacity) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            }
    
            ensureExplicitCapacity(minCapacity);
        }
    
        private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
    
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
        private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                newCapacity = hugeCapacity(minCapacity);
            // minCapacity is usually close to size, so this is a win:
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
    

    通过源码可以看出:ArrayList的实现主要就是用了一个Object的数组,用来保存所有的元素,以及一个size变量用来保存当前数组中已经添加了多少元素。

    执行add方法时,主要分为两步:

    • 首先判断elementData数组容量是否满足需求——》判断如果将当前的新元素加到列表后面,列表的elementData数组的大小是否满足,如果size + 1的这个需求长度大于了elementData这个数组的长度,那么就要对这个数组进行扩容;

    • 之后在elementData对应位置上设置元素的值。

    2. 线程不安全的两种体现

    2.1 数组越界异常 ArrayIndexOutOfBoundsException

    由于ArrayList添加元素是如上面分两步进行,可以看出第一个不安全的隐患,在多个线程进行add操作时可能会导致elementData数组越界。

    具体逻辑如下:

    1. 列表大小为9,即size=9

    2. 线程A开始进入add方法,这时它获取到size的值为9,调用ensureCapacityInternal方法进行容量判断。

    3. 线程B此时也进入add方法,它获取到size的值也为9,也开始调用ensureCapacityInternal方法。

    4. 线程A发现需求大小为10,而elementData的大小就为10,可以容纳。于是它不再扩容,返回。

    5. 线程B也发现需求大小为10,也可以容纳,返回。

    6. 线程A开始进行设置值操作, elementData[size++] = e 操作。此时size变为10。

    7. 线程B也开始进行设置值操作,它尝试设置elementData[10] = e,而elementData没有进行过扩容,它的下标最大为9。于是此时会报出一个数组越界的异常ArrayIndexOutOfBoundsException.

    2.2 元素值覆盖和为空问题

    elementData[size++] = e 设置值的操作同样会导致线程不安全。从这儿可以看出,这步操作也不是一个原子操作,它由如下两步操作构成:

    elementData[size] = e;
    size = size + 1;
    

    在单线程执行这两条代码时没有任何问题,但是当多线程环境下执行时,可能就会发生一个线程的值覆盖另一个线程添加的值,具体逻辑如下:

    1. 列表大小为0,即size=0

    2. 线程A开始添加一个元素,值为A。此时它执行第一条操作,将A放在了elementData下标为0的位置上。

    3. 接着线程B刚好也要开始添加一个值为B的元素,且走到了第一步操作。此时线程B获取到size的值依然为0,于是它将B也放在了elementData下标为0的位置上。

    4. 线程A开始将size的值增加为1

    5. 线程B开始将size的值增加为2

    这样线程AB执行完毕后,理想中情况为size为2,elementData下标0的位置为A,下标1的位置为B。而实际情况变成了size为2,elementData下标为0的位置变成了B,下标1的位置上什么都没有。并且后续除非使用set方法修改此位置的值,否则将一直为null,因为size为2,添加元素时会从下标为2的位置上开始。

    3. 代码示例

    如下,通过两个线程对ArrayList添加元素,复现上面的两种不安全情况。

    import java.util.ArrayList;
    import java.util.List;
    
    public class ArrayListSafeTest {
    
        public static void main(String[] args) throws InterruptedException {
    
            final List<Integer> list = new ArrayList<Integer>();
            // 线程A将1-1000添加到列表
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    for (int i = 1; i < 1000; i++) {
                        list.add(i);
    
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
    
                }
    
            }).start();
            
            // 线程B将1001-2000添加到列表
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    for (int i = 1001; i < 2000; i++) {
                        list.add(i);
    
                        try {
                            Thread.sleep(1); 
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
    
                }
    
            }).start();
            
            Thread.sleep(1000);
    
            // 打印所有结果
            for (int i = 0; i < list.size(); i++) {
                System.out.println("第" + (i + 1) + "个元素为:" + list.get(i));
            }
        }
    }
    

    执行过程中,两种情况出现如下:

    4. ArrayList线程安全处理

    4.1 Collections.synchronizedList

    最常用的方法是通过 Collections 的 synchronizedList 方法将 ArrayList 转换成线程安全的容器后再使用。

    List<Object> list =Collections.synchronizedList(new ArrayList<Object>);
    

    4.2 为list.add()方法加锁

    synchronized(list.get()) {
    list.get().add(model);
    }
    

    4.3 CopyOnWriteArrayList

    使用线程安全的 CopyOnWriteArrayList 代替线程不安全的 ArrayList。

    List<Object> list1 = new CopyOnWriteArrayList<Object>();
    

    4.4 使用ThreadLocal

    使用ThreadLocal变量确保线程封闭性(封闭线程往往是比较安全的, 但由于使用ThreadLocal封装变量,相当于把变量丢进执行线程中去,每new一个新的线程,变量也会new一次,一定程度上会造成性能[内存]损耗,但其执行完毕就销毁的机制使得ThreadLocal变成比较优化的并发解决方案)。

    ThreadLocal<List<Object>> threadList = new ThreadLocal<List<Object>>() {
        @Override
        protected List<Object> initialValue() {
              return new ArrayList<Object>();
        }
    };
    

    参考

    • blog.csdn.net/u012859681/article/details/78206494

    • www.cnblogs.com/mabaoqing/p/7446938.html

    END

    作者:雪山上的蒲公英
    www.cnblogs.com/zjfjava/p/10217720.html
    
    觉得本文对你有帮助?请分享给更多人
    
    关注「全栈开发者社区」加星标,提升全栈技能
    本公众号会不定期给大家发福利,包括送书、学习资源等,敬请期待吧!
    如果感觉推送内容不错,不妨右下角点个在看转发朋友圈或收藏,感谢支持。
    好文章,留言、点赞、在看和分享一条龙吧❤️
    
    展开全文
  • 多线程全局变量:1.定义只读的全局变量时,必须加final修饰,即使是private的,防止被反射修改。2.对于需要多次读写的全局变量,一定要用ThreadLocal封装,避免多线程并发时变量被多次赋值等不安全的一些现象。...

    多线程全局变量:
    1.定义只读的全局变量时,必须加final修饰,即使是private的,防止被反射修改。
    2.对于需要多次读写的全局变量,一定要用ThreadLocal封装,避免多线程并发时变量被多次赋值等不安全的一些现象。(静态ThreadLocal要对初始化方法加锁)

    线程池的使用:

    Executors.newCachedThreadPool().execute(Task task)

    解决办法:
    1.使用线程安全的集合元素:java.util.concurrent.CopyOnWriteArrayList

    2.为list.add()等方法加锁

    synchronized(threadList.get()) {
        threadList.get().add(model);
    }

    3.使用ThreadLocal

    ThreadLocal<List<CapaCityModel>> threadList = new ThreadLocal<List<CapaCityModel>>(){
        @Override 
        protected List<CapaCityModel> initialValue() { 
            return new ArrayList<CapaCityModel>(); 
        } 
    };

    这里再扩展一下解决并发问题的两种常用的方案并进行对比:

    1.使用synchronized来修饰,此方法相当于单线程队列执行,需要等待,有损性能,好处是不会增加内存的额外开销。

    2.使用ThreadLocal封装变量,相当于把变量丢进执行线程中去,每new一个新的线程,变量也会new一次(不一定每次都new,这个要看程序怎么写。),对性能没有影响,但会增加系统额外的内存开销,但其执行完毕就销毁的机制使得ThreadLocal变成比较优化的并发解决方案。

     

    转载于:https://www.cnblogs.com/mabaoqing/p/7446938.html

    展开全文
  • 一、单线程 1. 异常情况举例 只要抛出出现异常,可以肯定的是代码一定有错误的地方。先来看看都有哪些情况会出现ConcurrentModificationException异常,下面以ArrayList remove 操作进行举例: 使用的数据集合...
  • import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class TestArrayListSafe { public static void main(String ...
  • import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; /** * @Auther: YongXuezhen ... * @Description: 多线程情况下集合类不安全的问题,add方法没有加锁 */ public class ContainNotSaf...
  • 多线程场景下使用 ArrayList,要注意这几点! ArrayList 不是线程安全的,这点很多人都知道,但是线程不安全的原因及表现,怎么在多线程情况下使用ArrayList,可能不是很清楚,这里总结一下。 1. 源码分析 查看 ...
  • 多线程读多文本写入MongoDB

    千次阅读 2015-01-29 19:34:46
    前面有一篇博客写的是多线程读文本写入OracleNoSQL,但是写入的效率很慢:三个文件夹(三个线程分别读里面的文本,共有4.3G*3大小的原始数据,花费时间大约为5-6小时)自己就想对比下写入MongoDB的效率和写入Oracle...
  • 模拟ArrayList多线程环境下线程不安全 public class UnSafeArrayList { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); for (int i = 0; i < 30; i++...
  • 使用ArrayList多线程环境可能会出现ArrayIndexOutOfBoundsException 异常,这篇文章就来看看为什么会出现这个错误。 文章目录场景还原原因查找总结 场景还原 先看看下面的实例: public class ArrayListConcurrent...
  • 线程不安全的ArrayList

    千次阅读 2017-01-15 23:02:49
    概述java.util.ArrayList不是线程安全的,当有线程并发读写ArrayList的时候,ArrayList会抛出如下异常java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification...
  • ()) 都是线程安全的list集合,但是他们在多线程的情况下虽然保证了线程安全,但是效率太低,因为在读取和插入元素的时候都会锁住整个对象, CopyOnWriteArrayList :特性基本与arrayList一致,底层也是数组结构,使用...
  • 关于多线程读文件

    千次阅读 2017-12-20 16:22:15
    编写基于多线程的素数(是除了自身和 1 以外,没有其它素数因子的自然数)判定程序。 1、待判定的整数经过键盘录入后存放在.txt ...方法:将文件内容全部出来再用多线程分析。 package java高级程序设计多线程; im
  • 一:ArrayList不安全示例 使用ArrayList每次打印的集合数量可能会小于10000,而使用Vector每次都是10000 public class ListTest { public static void main(String[] args) throws InterruptedException { ...
  • 多线程得环境下,线程会争抢资源,导致java.util.ConcurrentModificationException 并发修改异常 解决方法: Vector 将ArrayList 替换成为Vector 原理: *将指定的元素插入到此Vector的指定位置。 将当前在该位置...
  • 一、ArrayList线程不安全演示 package com.yuxx.juc; import java.util.ArrayList; import java.util.List; public class ListNotSafeDemo { public sta...
  • ArrayList线程不安全的,这点毋庸置疑。因为ArrayList的所有方法既没有加锁,也没有进行额外的线程安全处理。而Vector作为线程安全版的ArrayList,存在感总是比较低。因为无论是add、remove还是get方法都加上了...
  • 原因分析: 我后来通过百度搜索终于确定了问题根源:ArrayList 简单来说,ArrayList不适合多线程高并发的情况,会出现内部某些位置为null的情况。核心原因是,ArrayList的add的方法不是线程安全的,是非原子性的,...
  • ArrayList 线程安全问题

    2020-07-30 15:13:27
    ArrayList用在多线程环境中存在线程安全问题。关键的原因就是ArrayList底层实现,在新增元素时数组索引的移动操作。 ArrayList的add()方法源码: Java中 i++ 并非线程安全的,这样多个线程同时往一个ArrayList中加...
  • JUC之线程不安全的ArrayList、HashSet、HashMap1 线程不安全的ArrayList1.1 前言1.2 单线程下的ArrayList1.3 多线程下的ArrayList1.4 线程不安全的ArrayList,解决方案1.4.1 方案一: Vector1.4.2 方案二: ...
  • ArrayList多线程下的完全隐患 面试官最喜欢问到的关于ArrayList多线程下的三问是: 1. ArrayList是线程不安全的,请写一个不安全的例子出来? 2. 怎么解决呢? 3. 更好的解决方案呢? 1. ArrayList是线程不...
  • 手写 | ArrayList集合 底层采用数组方式 怎样保证集合存放无限大小—数组扩容技术 代码实现: package MyArraayList; import java.util.Arrays; /** * @author 孙一鸣 on 2020/3/3 */ public class ...
  • 大家都知道ArrayList线程不安全的,那我们如何写一个demo来证明ArrayList线程不安全的呢,并且我们有哪些方式可以解决ArrayList线程不安全呢? 首先,我们创建30个线程去往ArrayList中添加元素: public class ...
  • ArrayList是非线程安全的,也就是说在线程下进行读写,会出现异常。 那么ArrayList既然是非线程安全的,那么我们使用一些机制把它变为安全的就可以了。比如说替换成Vector,再或者是Collections,可以将...
  • ArrayList线程不安全的实例代码 package com.jian8.juc.collection; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** * 集合类不安全问题 * ArrayList */ public class ...
  • 1、谈谈Arraylist A. ArrayList 底层数据结构是数组,数组的特点就是可以快速随机访问,直接根据下标定位,缺点是插入和删除速度比较慢,需要移动元素。 B. ArrayList 每次扩容之后的大小为之前的 1.5 倍。默认初始...
  • 多线程读db,并将数据写入csv文件

    千次阅读 2014-09-23 18:19:46
    package com.ad.action; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStreamWriter;...import java.util.ArrayList; import java.util.List; impor
  • JAVA 多线程(读书笔记)

    千次阅读 2010-01-18 19:21:00
    目录生成线程的两种方法 线程的中断线程状态线程属性同步阻塞队列线程安全集合callable,Future执行器同步器线程和Swing 生成线程的两种方法实现Runnable,并作为参数传给Thread

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 51,682
精华内容 20,672
关键字:

多线程读arraylist