zoukankan      html  css  js  c++  java
  • ArrayList, Vector和CopyOnWriteArrayList对比学习

    ArrayList线程不安全的例子

    线程安全就是多线程访问时,采用加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据时脏数据。List接口下有两个实现,一个是ArrayList,另一个是Vector。从源码角度来看,因为Vector的方法前加了synchronized关键字,也就是同步。ArrayList是高效的,Vector则是线程安全的。

    ArrayList不是线程安全的举个例子:一个ArrayList,在添加一个元素的时候,它有大体上有两步来完成:

    1. 在内部数组的size索引处存放此元素;
    2. 增大size的值

    在单线程情况下,如果size是0,添加一个元素之后,此元素在位置0,而且size=1;

    在多线程情况下,假设有两个线程,线程A现将元素放在0位置。但是此时CPU调度线程A暂停线程B得到运行机会,线程B也向ArrayList中添加元素,因为此时size仍然等于0(注意线程A只完成了添加的第一步,后面修该size的步骤还没做),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加size的值。对于这个ArrayList来说,元素实际上只有一个,存放在位置0,二size却等于2。

    附:ArrayList的add方法:

    1 public boolean add(E e) {
    2     // Increments modCount!!
    3     ensureCapacityInternal(size + 1);
    4     // 现在size处放置元素, 然后在增加size
    5     elementData[size++] = e;
    6     return true;
    7 }

    测试ArrayList线程不安全的demo:

     1 public class UnsafeArrayListDemo implements Runnable {
     2     private List<Integer> list = new ArrayList<Integer>();
     3 
     4     public void run() {
     5         try {
     6             Thread.sleep((int)Math.random());
     7         } catch (Exception e) {
     8             e.printStackTrace();
     9         }
    10         list.add(1);
    11     }
    12 
    13     public static void main(String[] args) throws Exception {
    14         ThreadGroup group = new ThreadGroup("group");
    15         UnsafeArrayListDemo unsafeArrayListDemo = new UnsafeArrayListDemo();
    16         for(int i=0; i<10000; i++) {
    17             Thread t = new Thread(group, unsafeArrayListDemo, String.valueOf(i));
    18             t.start();
    19         }
    20         // 等待线程组执行完毕
    21         while(group.activeCount() > 0) {
    22             Thread.sleep(100);
    23         }
    24         System.out.println(unsafeArrayListDemo.list.size());
    25     }
    26 }

    现在看下Vector中的add方法:

    1 public synchronized boolean add(E e) {
    2     modCount++;
    3     ensureCapacityHelper(elementCount + 1);
    4     elementData[elementCount++] = e;
    5     return true;
    6 }

    基本上和ArrayList一样,都是先添加,然后对size自增,唯一不同的是这个方法上加了关键字synchronized。可以在ArrayList的demo换成Vector来测试(本人已经测试过了,就不附代码了,直接替换ArrayList就好了)。Vector相对于ArrayList也会很暴力,为了线程安全就对方法加上了synchronized。

    Vector的方法在单个进行调用的时候虽然是线程安全的,但是进行方法的复合操作的时候仍然是线程不安全的,还需要客户端来进行加锁。

    Vector复合操作不安全的例子

     1 public class VectorDemo {
     2     // 获取最后一个元素
     3     public static Object getLast(Vector list) {
     4         int lastIndex = list.size() - 1;
     5         return list.get(lastIndex);
     6     }
     7     // 删除最后一个元素
     8     public static void deleteLast(Vector list) {
     9         int lastIndex = list.size() - 1;
    10         list.remove(lastIndex);
    11     }
    12 }

    像这种先获取值,然后进行操作都是不安全的,简单的方法就是在方法内部进行加锁。问题来了,怎么加锁呢?

  • 相关阅读:
    Mybatis批处理
    Mybatis兼容C3P0连接池
    一对多,多对一查询
    缓存
    动态sql
    mybatis 日志记录
    python学习day07-encode和decode
    python学习day07---三级目录优化
    python学习day06练习---三级目录
    python学习day06--02字典增删差改以及字符串的一些方法
  • 原文地址:https://www.cnblogs.com/tuhooo/p/9333797.html
Copyright © 2011-2022 走看看