Chapter 3 Vector类还需要同步吗

来源:互联网 发布:雅思6 知乎 编辑:程序博客网 时间:2024/06/15 08:37

1 概述

1.1 Vector与ArrayList

Vector和ArrayList同样是用来存储数量可变的对象的容器,其二者用法相似,但是也有一些不同点。其中一个重要的不同是,Vector是线程安全的,它的方法如add,get等都是被synchronize关键字修饰的,而ArrayList没有。类似的情形也出现在HashTable与HashMap两个类的对比上。

1.2 绝对的线程安全

绝对的线程安全是Brian Goetz给出的一个很严格的线程安全的定义,其表示:不管运行环境如何,调用者都不需要任何额外的同步措施。一个类要达到绝对的线程安全的标准代价是很大的。在Java API中标注线程安全的类大多是都不是绝对的线程安全的,例如Vector。

2 Vector也需要同步

即使一个类的所有方法都被synchronize关键字修饰了也并不意味着调用它的时候一直不需要同步手段。例如下面的一段对Vector类的测试代码:

import java.util.Vector; /** * Created by fubinhe on 16/9/11. */public class VectorMultiThread {    public static void main(String[] args) {        final Vector<Integer> vec = new Vector<>();         while (true) {            for (int i = 0;i < 10;++i) {                vec.add(i);            }            new Thread(new Runnable() {                @Override                public void run() {                    for (int i = 0;i < vec.size();++i) {                        vec.remove(i);                    }                }            }).start();            new Thread(new Runnable() {                @Override                public void run() {                    for (int i = 0;i < vec.size();++i) {                        System.out.println(vec.get(i));                    }                }            }).start();            while (Thread.activeCount() >= 5); //避免创建过多的线程        }    }}

这段代码有两类线程,第一类是将之前添加到vec中的数依次删除,而第二类是将vec中的数依次打印出来。运行这段代码出现角标越界异常的,如下图所示。究其原因是因为,在某个时间点上删除线程删除了某个序号的元素,而有一个打印线程恰好要访问这个序号的元素,这个时候就会抛出ArrayIndexOutOfBoundsException。解决方法是,删除线程和打印线程想要访问vec变量时,首先对其同步,修改后的代码如下所示:

/** * Created by fubinhe on 16/9/11. */public class VectorMultiThread {    public static void main(String[] args) {        final Vector<Integer> vec = new Vector<>();         while (true) {            for (int i = 0;i < 10;++i) {                vec.add(i);            }            new Thread(new Runnable() {                @Override                public void run() {                    synchronized (vec) {                        for (int i = 0;i < vec.size();++i) {                            vec.remove(i);                        }                    }                }            }).start();            new Thread(new Runnable() {                @Override                public void run() {                    synchronized (vec) {                        for (int i = 0;i < vec.size();++i) {                            System.out.println(vec.get(i));                        }                    }                }            }).start();            while (Thread.activeCount() >= 5); //避免创建过多的线程        }    }}
3 相对的线程安全

我们通常意义上讲的线程安全就是一种相对的线程安全,其可以确保对一个对象单独的操作线程是安全的,但是对于特定顺序的连续调用依然需要使用额外的同步机制来保证运行结果的同步性。在Java中,大部分的线程安全类都是属于这种类型的,如Vector,HashTable以及Collections.synchronizedCollection()方法包装的集合类。


0 0
原创粉丝点击