java ArrayList vector 线程安全

java ArraList和Vector有什么区别?或许我们都知道的一点是ArrayList是非线程安全的,而Vector是线程安全的。什么是线程安全呢?线程安全就是多个线程对同一个对象进行插入操作时,同一时间段内只有一个线程能够对其进行操作。我们进行一下测试:

使用多个线程同时操作一个ArrayList:

import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;

public class Test{
	public static ArrayList<Object> arrayList = new ArrayList<Object>();
	public static CountDownLatch countDownLatch = new CountDownLatch(10);
	public static int x = 0;
	public static void main(String[] args0) throws InterruptedException{
		Threads []threads = new Threads[10];
		for(int i=0;i<10;i++){
			threads[i] = new Threads();
			threads[i].start();
		}
		countDownLatch.await();
		for(int i=0;i<arrayList.size();i++){
			if(i==(arrayList.size()-1))
				System.out.println(arrayList.size());
			System.out.println(arrayList.get(i));
		}
	}
	static class Threads extends Thread{
		public void run(){
			for(int i=0;i<100;i++){
				arrayList.add(Thread.currentThread().getName()+"Thread"+x++);
			}
			countDownLatch.countDown();
		}
	}
}
其中我们再main函数中创建了一个静态的ArrayList,新建了十个线程,每个线程为ArrayList添加100个元素,并且新建了一个CountDownLatch用于main函数等待线程执行结束。多进行几次测试发现大多数情况下ArrayList的大小并没有1000,有时候还报错
Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: 33
	at java.util.ArrayList.add(ArrayList.java:459)
	at Test$Threads.run(Test.java:24)
这是为什么?     我们看一看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) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
其中ensureCapacityInternal 函数函数源码是这样的:

    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);
    }

分析上面的两种错误类型:

第一种:   两个线程同时读取错误到了ArrayList的大小,然后进行了更改,更直观的是A线程读取ArrayList的大小为5,线程B读取到的也是5,这样就导致连个线程再同一个位置写入了数据,那么自然就导致了arrayList大小和预期不同。

第二种:   ArrayList越界: 两个(多个)线程同时判断是否需要扩容,发现并不需要。但是当进行插入操作的时候就发现出现了越界。所以报错。


那么Vector是怎么进行线程安全操作的呢?

我们可以从Vector的源码中就可以看出:

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

我们以add的代码为例进行查看:   可以看到和ArrayList的差别就是加上了Synchronized,是这个方法同时只能被一个线程访问:

我们测试一个synchronized方法:

public class Test{
	public static void main(String[] args0){
		ThreadTemp threadTemp = new ThreadTemp();
		Thread thread1 = new Thread(threadTemp);
		Thread thread2 = new Thread(threadTemp);
		thread1.start();
		thread2.start();
	}
	static class ThreadTemp implements Runnable{
		public synchronized void run() {
			System.out.println(Thread.currentThread().getName()+"开始执行");
			try {
				Thread.sleep(10000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"执行完成");
		}
	}
}
代码中为了保证我们能够让两个线程同时运行一个Runnable实例,我们使用ThreadTemp类实现了Runnable接口,并把run方法改为synchronized的。新建两个Thread类来执行这个类。结果发现执行结果如下:
Thread-0开始执行
Thread-0执行完成
Thread-1开始执行
Thread-1执行完成
只能有一个线程进入此方法区 。这就是synchronized的作用。那么我们现在更改一个上面的代码。使用vector来看看是否还会出现上面的问题。

import java.util.Vector;
import java.util.concurrent.CountDownLatch;

public class Test{
	public static Vector<Object> vector = new Vector<Object>();
	public static CountDownLatch countDownLatch = new CountDownLatch(10);
	public static int x = 0;
	public static void main(String[] args0) throws InterruptedException{
		Threads []threads = new Threads[10];
		for(int i=0;i<10;i++){
			threads[i] = new Threads();
			threads[i].start();
		}
		countDownLatch.await();
		for(int i=0;i<vector.size();i++){
			if(i==(vector.size()-1))
				System.out.println(vector.size());
			System.out.println(vector.get(i));
		}
	}
	static class Threads extends Thread{
		public void run(){
			for(int i=0;i<100;i++){
				vector.add(Thread.currentThread().getName()+"Thread"+x++);
			}
			countDownLatch.countDown();
		}
	}
}

经过多次测试发现并没有发现任何问题。每一次的数据结果都和预期相同。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值