线程安全的list该如何实现?

TheDisguiser 2020-05-26 21:37:16 java常见问答 7708

List集合相信大家都经常用吧,但是可惜的是它不是线程安全的,那么,该如何把list变成一个线程安全的集合呢?下面就来看看吧。

首先我们知道,ArrayList不是一个线程安全的集合,因此在实现多线程开发时,我们不能够使用多个线程同时操作List。如果我们让一个线程向 ArrayList中添加元素,又让另一个线程从其中删除元素,就会出现线程安全问题,抛出ConcurrentModificationException异常。

Vector

我们要知道Vector,这是一个可变长度的数组,它类似于ArrayList,但与ArrayList不同,Vector是绝对线程安全的,它的机制就是会给几乎所有的public方法都加上synchronized关键字。但是,由于加锁会导致性能降低到一定程度,在不需要并发访问同一对象时,像这样强制性的同步机制就显得非常多余了,所以Vector现在已经被抛弃啦。

Collections

但是办法总是想出来的,在Vector和HashTable相继被弃用后,它们被ArrayList及HashMap代替,但ArrayList及HashMap它们不是线程安全的,所以java中就有了Collections这么一个工具类,它能够提供相应的包装方法把ArrayList和HashMap包装成线程安全的集合。实现代码如下:

ListsynArrayList = Collections.synchronizedList(new ArrayList());

读写速度测试:

 import java.util.*;
 import java.util.Collections;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 /**
  * 
  * @author tanhuiling
  *Collections.synchronizedList和CopyOnWriteArrayList性能分析
  */
 public class ListTest
 {
     private static List < String > arrayList = Collections.synchronizedList(new ArrayList < String > ());
     private static List < String > copyOnWriteArrayList = new CopyOnWriteArrayList < String > ();
     private static CountDownLatch cdl1 = new CountDownLatch(2);
     private static CountDownLatch cdl2 = new CountDownLatch(2);
     private static CountDownLatch cdl3 = new CountDownLatch(2);
     private static CountDownLatch cdl4 = new CountDownLatch(2);
     //ArrayList写线程
     static class ArrayAddThread extends Thread
     {
         @Override
         public void run()
         {
             // TODO Auto-generated method stub
             for (int i = 0; i < 50000; i++)
             {
                 arrayList.add(String.valueOf(i));
             }
             cdl1.countDown();
         }
     }
     //ArrayList读线程
     static class ArrayGetThread extends Thread
     {
         @Override
         public void run()
         {
             // TODO Auto-generated method stub
             int size = arrayList.size();
             for (int i = 0; i < size; i++)
             {
                 arrayList.get(i);
             }
             cdl2.countDown();
         }
     }
     //CopyOnWriteArrayList写线程
     static class CopyAddThread extends Thread
     {
         @Override
         public void run()
         {
             // TODO Auto-generated method stub
             for (int i = 0; i < 50000; i++)
             {
                 copyOnWriteArrayList.add(String.valueOf(i));
             }
             cdl3.countDown();
         }
     }
     //CopyOnWriteArrayList写线程
     static class CopyGetThread extends Thread
     {
         @Override
         public void run()
         {
             // TODO Auto-generated method stub
             int size = copyOnWriteArrayList.size();
             for (int i = 0; i < size; i++)
             {
                 copyOnWriteArrayList.get(i);
             }
             cdl4.countDown();
         }
     }
     public static void main(String[] args) throws InterruptedException
     {
         long start1 = System.currentTimeMillis();
         new ArrayAddThread()
             .start();
         new ArrayAddThread()
             .start();
         cdl1.await();
         long end1 = System.currentTimeMillis();
         System.out.println("ArrayList写操作时间:" + (end1 - start1));
         long start3 = System.currentTimeMillis();
         new CopyAddThread()
             .start();
         new CopyAddThread()
             .start();
         cdl3.await();
         long end3 = System.currentTimeMillis();
         System.out.println("CopyOnWriteArrayList的写操作时间:" + (end3 - start3));
         long start2 = System.currentTimeMillis();
         new ArrayGetThread()
             .start();
         new ArrayGetThread()
             .start();
         cdl2.await();
         long end2 = System.currentTimeMillis();
         System.out.println("ArrayList读操作时间:" + (end2 - start2));
         long start4 = System.currentTimeMillis();
         new CopyGetThread()
             .start();
         new CopyGetThread()
             .start();
         cdl4.await();
         long end4 = System.currentTimeMillis();
         System.out.println("CopyOnWriteArrayList的读操作时间:" + (end4 - start4));
     }
 }

结果:

ArrayList写操作时间:30
CopyOnWriteArrayList的写操作时间:5710
ArrayList读操作时间:28
CopyOnWriteArrayList的读操作时间:2

以上就是关于list实现线程安全的所有内容啦,如果还想要知道更多像list这样的java常见问答知识的话,就快来关注我们的网站了解吧。

推荐阅读:

线程安全问题是什么?要如何解决?

线程安全的集合是什么集合?都有哪些线程安全集合?

线程安全的单例模式有几种?有何特点?