Java中线程安全的容器

1、Collections包装的同步容器

在Collections类中,通过以下方法可以将一个非线程安全的容器包装为一个线程安全的容器:

//线程安全的List,其类型为SynchronizedList或SynchronizedRandomAccessList
List<Object> list = Collections.synchronizedList(new ArrayList<>());

//线程安全的Set,其类型为SynchronizedSet
Set<Object> set = Collections.synchronizedSet(new HashSet<>());

//线程安全的Map,其类型为synchronizedMap
Map<Object, Object> map = Collections.synchronizedMap(new HashMap<>());

除此之外还有SynchronizedCollection、SynchronizedSortedSet、SynchronizedSortedMap、SynchronizedNavigableSet和SynchronizedNavigableMap都是线程安全的。

它们的实现原理都是直接将操作容器的方法通过synchronized同步关键字包裹起来,以SynchronizedList为例:

public boolean equals(Object o) {
    if (this == o)
        return true;
    synchronized (mutex) {return list.equals(o);}
}
public int hashCode() {
    synchronized (mutex) {return list.hashCode();}
}

public E get(int index) {
    synchronized (mutex) {return list.get(index);}
}
public E set(int index, E element) {
    synchronized (mutex) {return list.set(index, element);}
}
public void add(int index, E element) {
    synchronized (mutex) {list.add(index, element);}
}
public E remove(int index) {
    synchronized (mutex) {return list.remove(index);}
}

public int indexOf(Object o) {
    synchronized (mutex) {return list.indexOf(o);}
}
public int lastIndexOf(Object o) {
    synchronized (mutex) {return list.lastIndexOf(o);}
}

public boolean addAll(int index, Collection<? extends E> c) {
    synchronized (mutex) {return list.addAll(index, c);}
}
......

2、JDK早期实现的同步容器

Vector、Stack 和 Hashtable是JDK1.5之前提供的同步容器,其实现原理与SynchronizedCollection基本类似,都是通过synchronized 修饰操作容器的方法实现的,只不过它们操作容器的方法都是自己实现的,而不是简单地包装其他非线程安全的容器的方法。以下为Vector中的一段核心源码:

public synchronized void removeElementAt(int index) {
    modCount++;
    if (index >= elementCount) {
        throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                 elementCount);
    }
    else if (index < 0) {
        throw new ArrayIndexOutOfBoundsException(index);
    }
    int j = elementCount - index - 1;
    if (j > 0) {
        System.arraycopy(elementData, index + 1, elementData, index, j);
    }
    elementCount--;
    elementData[elementCount] = null; /* to let gc do its work */
}

public synchronized void insertElementAt(E obj, int index) {
    modCount++;
    if (index > elementCount) {
        throw new ArrayIndexOutOfBoundsException(index
                                                 + " > " + elementCount);
    }
    ensureCapacityHelper(elementCount + 1);
    System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
    elementData[index] = obj;
    elementCount++;
}

public synchronized void addElement(E obj) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = obj;
}

public synchronized boolean removeElement(Object obj) {
    modCount++;
    int i = indexOf(obj);
    if (i >= 0) {
        removeElementAt(i);
        return true;
    }
    return false;
}

public synchronized void removeAllElements() {
    modCount++;
    // Let gc do its work
    for (int i = 0; i < elementCount; i++)
        elementData[i] = null;

    elementCount = 0;
}

juc包中的并发容器

JDK1.5之前的线程安全的容器中的方法都是通过synchronized 来保证的,这样有个最大的问题,那就是性能差。因为它们在方法实现上都是使用synchronized 锁住整个容器,因此访问容器的方法串行度非常高。

在JDK1.5及之后的版本中,在java.util.concurrent并发包中提供了很多的并发容器,包含了我们常用的四大类容器:List、Map、Set 和 Queue。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值