您的位置:首页 > 编程语言 > Java开发

java ArrayList vector 线程安全

2016-09-16 16:08 232 查看
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();
}
}
}

经过多次测试发现并没有发现任何问题。每一次的数据结果都和预期相同。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Exception in thread