java线程学习二

来源:互联网 发布:java图形化界面开发 编辑:程序博客网 时间:2024/05/18 03:08

同步容器类:之所以是同步容器类是表示其对容器执行的是串行操作

  1. 同步容器都是线程安全的,因为不支持并发,所以其都会有锁,代表类Vector和HashTable,其封装器类是Collections.synchronizedXXX();一般方法是是XXX代表是哪一种容器,那么其形参就是哪一种容器。但是同步容器的安全都指的是一种单一操作,加入若有一个复合操作,那么就不存在安全了。
  2. 同步容器的非安全因素
    在同步容器里面虽然方法都加上了synchronized关键字,但是在执行复合操作的时候例如循环遍历的时候就会出现一些问题,在Vetor源码里面可以看到,Vetor的每一个方法都是一个原子操作,那么当线程在访问的时候,那么当我们执行的是单一操作的时候就会是一中安全的操作:
    • 比如:
Vetor vetor =new Vetor();public void fuhe()//一种复合操作{vetor.setSize(10);return vetor.size();}public void danyi()//一{vetor.setSize(20);}

此时假设有两个线程,那么在调用复合的时候由于vetor的同步方方法肯定是其中一个线程在等另一个线程释放锁,那么在第一个线程假设A释放setSize的锁后另一个线程立即获得该锁,再次执行setSize方法,那么此时方法fuhe后面的一句返回的值就不一定正确了。这就是同步容器的复合操作。
- 解决方法:
当一个线程在执行fuhe操作的时候持有一个vetor的锁,那么即使我在复合操作,那么也不可能造成这种情况

public void fuhe(){  synchornized(vetor)    {       vetor.setSize(10);       return vetor.size();    }}
  1. 同步容器的迭代 Collections.synchronizedList代码示例。
    所以在对同步容器迭代操作的时候最好都加上一个锁
    同理迭代也是一种符合操作,那么在对其操作的时候由于同步容器的限制,肯定也会引发上述问题,
List list = Collections.synchronizedList(new ArrayList());      ...  synchronized (list) {      Iterator i = list.iterator(); // Must be in synchronized block      while (i.hasNext())          foo(i.next());  }

即在同步的时候必须用synchronized对所需要的对象进行原子性操作
- 及时失败:当察觉到容器在迭代开始后被修改后会抛出一个未检查的ConcurrentModificationException;
- 若一致性:可以容忍容器并发的被修改。
3. 克隆容器:
假设在迭代容器的时候不希望加入锁,那么可以用克隆容器间接来实现,并且在克隆的容器上面进行迭代。

List<E> a =new ArrayList<E>;List<E> B= a;

并发容器类:

  1. ConCurrentHashMap:
    • 翻看其源码unanimous发现,其所有域都是final,但是未用过synchornized,其实现方式是一个分段锁的形式,使得任意的读取线程都可以对其进行访问,而且读取和写入线程都可以对其进行访问。
    • 在 ConCurrentHashMap里面有的在同步容器里面是复合操作的时间在 ConCurrentHashMap里面已经整合为一个原子操作了。
  2. CopyOnWriteArrayList:
    其内部是基于一个数组来实现的:
    /** The array, accessed only via getArray/setArray. */    private volatile transient Object[] array;public CopyOnWriteArrayList(Collection<? extends E> c) {        Object[] elements = c.toArray();        // c.toArray might (incorrectly) not return Object[] (see 6260652)        if (elements.getClass() != Object[].class)            elements = Arrays.copyOf(elements, elements.length, Object[].class);        setArray(elements);    }

在每次修改其内容时,每次都会创建一个新的数组副本;

 public E set(int index, E element) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            E oldValue = get(elements, index);            if (oldValue != element) {                int len = elements.length;                Object[] newElements = Arrays.copyOf(elements, len);                newElements[index] = element;                setArray(newElements);            } else {                // Not quite a no-op; ensures volatile write semantics                setArray(elements);            }            return oldValue;        } finally {            lock.unlock();        }    }

而且这个数组是volte修饰,也就是共享的,而且这个修改他的引用并未发布或者溢出,这样任何一个线程来访问的时候都会获取最新的数组。而且多个线程之间互不干扰。
3. 其弊端便是开销太大,加入一个需求是迭代次数远大于进行操作次数那么这个容器就比较适合

HashMap,ConcurrentMap,SynchronizedMap的区别

  1. HashMap,一键值对的形式存放数据的容器,
  2. ConcurrentMap,并发容器,有锁,但是粒度非常细。
  3. SynchronizedMap同步容器,对象级别的锁,
0 0
原创粉丝点击