简单了解并发容器

阻塞队列

阻塞队列用到了类似于生产者-消费者模式,和普通队列不同,在队列为空的时候消费动作会被阻塞,在队列满的时候生产动作会被阻塞。

ArrayBlockingQueue

成员变量

// 底层存储元素的数组
final Object[] items;

// 在索引处取出元素
int takeIndex;

// 在索引处放入元素
int putIndex;

// 当前数组内的元素个数
int count;

// 用ReentrantLock实现并发安全
final ReentrantLock lock;

// 用Condition notEmpty实现消费者阻塞等待
private final Condition notEmpty;

// 用Condition notFull实现生产者阻塞等待
private final Condition notFull;

// 迭代器
transient Itrs itrs = null;

put()

public void put(E e) throws InterruptedException {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    // 使用可打断加锁
    lock.lockInterruptibly();
    try {
        // 阻塞队列特性,队列满生产阻塞,放到同步队列
        while (count == items.length)
            notFull.await();
        // 到这里有两种可能,一个是可以正常放入新元素;另外就是上面的while阻塞等待条件被破坏,有任务被消费了
        // 加入队列
        enqueue(e);
    } finally {
        // 释放锁
        lock.unlock();
    }
}

enqueue(e)

private void enqueue(E x) {
    final Object[] items = this.items;
    // 放入元素
    items[putIndex] = x;
    // 为了避免指针超界限
    if (++putIndex == items.length)
        putIndex = 0;
    count++;
    // 可以让同步队列内的消费者被唤醒
    notEmpty.signal();
}

take()

整体流程和之前的put()差不多,只不过这里的while循环的条件是队列为空

public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0)
            notEmpty.await();
        return dequeue();
    } finally {
        lock.unlock();
    }
}

dequeue()

整体流程和之前的enqueue()差不多

private E dequeue() {
    final Object[] items = this.items;
    @SuppressWarnings("unchecked")
    E x = (E) items[takeIndex];
    items[takeIndex] = null;
    if (++takeIndex == items.length)
        takeIndex = 0;
    count--;
    if (itrs != null)
        itrs.elementDequeued();
    notFull.signal();
    return x;
}

LinkedBlockingDeque

成员变量

static final class Node<E> {
    
    E item;
    Node<E> prev;
    Node<E> next;

    Node(E x) {
        item = x;
    }
}

// 链表的头节点
transient Node<E> first;

// 链表的尾节点
transient Node<E> last;

// 链表内的元素数量
private transient int count;

// 链表最大可装载的节点数量
private final int capacity;

// 用ReentrantLock实现并发安全
final ReentrantLock lock = new ReentrantLock();

// 用Condition notEmpty实现消费者阻塞等待
private final Condition notEmpty = lock.newCondition();

// 用Condition notFull实现生产者阻塞等待
private final Condition notFull = lock.newCondition();

put()

public void putLast(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    Node<E> node = new Node<E>(e);
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        // 尾插法加入新节点
        while (!linkLast(node))
            notFull.await();
    } finally {
        lock.unlock();
    }
}
linkLast()
private boolean linkLast(Node<E> node) {
    // 如果链表节点数到达最大值,返回false,把生产者加入同步队列阻塞
    if (count >= capacity)
        return false;
    // 尾插法插入新元素
    Node<E> l = last;
    node.prev = l;
    last = node;
    if (first == null)
        first = node;
    else
        l.next = node;
    ++count;
    // 唤醒消费者同步队列线程
    notEmpty.signal();
    return true;
}

take()

public E takeFirst() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        E x;
        while ( (x = unlinkFirst()) == null)
            notEmpty.await();
        return x;
    } finally {
        lock.unlock();
    }
}
unlinkFirst()
private E unlinkFirst() {
    // 移除头部节点
    Node<E> f = first;
    if (f == null)
        return null;
    Node<E> n = f.next;
    E item = f.item;
    f.item = null;
    f.next = f; // help GC
    first = n;
    if (n == null)
        last = null;
    else
        n.prev = null;
    --count;
    // 唤醒生产者同步队列的线程
    notFull.signal();
    return item;
}

写时复制容器

什么是写时复制?

写时复制是一种懒加载的设计思想,例如linux创建子进程,并不会拷贝父进程的数据,而是先用一个指针引用指向共享内存,等到父进程需要修改的时候,才会给子进程复制一份冲突的内存。

CopyOnWriteArrayList

成员变量

final transient ReentrantLock lock = new ReentrantLock();

// 存放元素的数组
private transient volatile Object[] array;

add()

public boolean add(E e) {
    // 上锁
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        // 创建新数组
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}

get()

没有加锁

private E get(Object[] a, int index) {
    return (E) a[index];
}

set()

和add()类似

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

remove()

public E remove(int index) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        E oldValue = get(elements, index);
        int numMoved = len - index - 1;
        if (numMoved == 0)
            setArray(Arrays.copyOf(elements, len - 1));
        else {
            // 这里专门把index位置漏掉
            Object[] newElements = new Object[len - 1];
            System.arraycopy(elements, 0, newElements, 0, index);
            System.arraycopy(elements, index + 1, newElements, index,
                             numMoved);
            setArray(newElements);
        }
        return oldValue;
    } finally {
        lock.unlock();
    }
}

CopyOnWriteArraySet

成员变量

底层使用

private final CopyOnWriteArrayList<E> al;

add()

和CopyOnWriteArrayList相同

remove()

和CopyOnWriteArrayList相同

contains()

public boolean contains(Object o) {
    Object[] elements = getArray();
    return indexOf(o, elements, 0, elements.length) >= 0;
}
indexof()

遍历CopyOnWriteArrayList

private static int indexOf(Object o, Object[] elements,
                           int index, int fence) {
    if (o == null) {
        for (int i = index; i < fence; i++)
            if (elements[i] == null)
                return i;
    } else {
        for (int i = index; i < fence; i++)
            if (o.equals(elements[i]))
                return i;
    }
    return -1;
}

分段锁容器

ConcurrentHashMap

  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值