日常记录——多线程与高并发—并发容器List实现类vector和CopyOnWriteArrayList

一、简介

1.vector:JDK1.0版本添加的类。继承于AbstractList,实现了List, RandomAccess, Cloneable这些接口。底层是数组结构,默认长度为10,每次扩容翻倍。Vector中的操作是线程安全的。因为大部分方法都使用synchronized修饰。
例如add方法:

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

get方法:

public synchronized E get(int index) {
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);

        return elementData(index);
    }

2.CopyOnWriteArrayList:JDK 1.5引入,一个线程安全的List实现类,底层为数据,在写入时加锁后复制一个比原来长度多一的数据,然后将写入数据添加到末尾,读的时候无锁共享。
add方法:添加元素时加锁,复制时内存占用翻倍。

public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

get方法:不加锁

public E get(int index) {
        return get(getArray(), index);
    }

注意:如果在t1线程读的时候,t2线程在写入,就会造成t1读的数据是t2放入之前的数据,所以只能保证最终的数据一致性,并不能保证数据的实时性。

二、代码举例

说明:创建两个线程分别向CopyOnWriteArrayList、Vector、ArrayList容器对象添加10000个元素,最后打印容器长度。CopyOnWriteArrayList结果:20000,Vector结果:20000,ArrayList:<20000(添加元素方法不是同步的),或者数组越界异常(两个线程在需要扩容的时候,t1执行了扩容,t2判断长度够用,直接放入元素,但t1只扩容了自己的位置,1个位置两个线程都要放元素,一个放完,另一个就抛出异常)。

public class synList {
    public static void main(String[] args) {
        CopyOnWriteArrayList<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
        Vector<Integer> vector = new Vector<>();
        List<Integer> list = new ArrayList<>();
        new Thread(() ->{
            for (int i = 0; i < 10000; i++) {
                copyOnWriteArrayList.add(new Integer(i));
            }
        }).start();
        new Thread(() ->{
            for (int i = 0; i < 10000; i++) {
                copyOnWriteArrayList.add(new Integer(i));
            }
        }).start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(copyOnWriteArrayList.size());
    }
}

三、vector和CopyOnWriteArrayList对比

1.vector:锁粒度大,排它锁,性能较低,但保证数据一致性。
2.CopyOnWriteArrayList:内存占用高,只能保证最终的数据一致性,并不能保证数据的实时性,但在读多写少的场景中效率高。

猜你喜欢

转载自blog.csdn.net/weixin_43001336/article/details/107217119