聊聊Java里经常使用的并发集合

前言

在咱们的程序开发过程当中,若是涉及到多线程环境,那么对于集合框架的使用就必须更加谨慎了,由于大部分的集合类在不施加额外控制的状况下直接在并发环境中直接使用可能会出现数据不一致的问题,因此为了解决这个潜在的问题,咱们要么在本身的业务逻辑中加上一些额外的控制,例如,或者咱们直接使用Java提供的可在并发环境中使用的集合类,这是一个简便并且高效的方法。那么咱们下面就来了解下Java提供了哪些“神器”可让咱们安全的使用集合。java

正文

非阻塞式安全列表 - ConcurrentLinkedDeque

ConcurrentLinkedDeque能够在并发环境中直接使用,所谓的非阻塞,就是当列表为空的时候,咱们还继续从列表中取数据的话,它会直接返回null或者抛出异常。下面列出来一些经常使用的方法。git

  • peekFirst()peekLast() :返回列表中首位跟末尾元素,若是列表为空则返回null。返回的元素不从列表中删除。
  • getFirst()getLast() :返回列表中首位跟末尾元素,若是列表为空则抛出NoSuchElementExceotion异常。返回的元素不从列表中删除。
  • removeFirst()removeLast() :返回列表中首位跟末尾元素,若是列表为空则抛出NoSuchElementExceotion异常。【返回的元素会从列表中删除】。

阻塞式安全列表 - LinkedBlockingDeque

LinkedBlockingDeque是一个阻塞式的线程安全列表,它跟 ConcurrentLinkedDeque最大的区别就是,当列表中元素满了或者为空的时候,咱们对该列表的操做不会当即返回,而是阻塞当前操做,直到该操做能够执行时才返回。咱们对比着上面ConcurrentLinkedDeque的经常使用方法,来看下LinkedBlockingDeque会有哪些不一致的地方呢?github

  • put() :插入元素至列表中,当表中元素已满的时候,该操做将会被阻塞,直到表中存在空余空间。
  • take() : 从列表中获取元素,当列表为空,该操做会被阻塞,直到列表不为空。
  • peekFirst()peekLast() :返回列表中首位跟末尾元素,若是列表为空则返回null。返回的元素不从列表中删除。
  • getFirst()getLast() :返回列表中首位跟末尾元素,若是列表为空则抛出NoSuchElementExceotion异常。返回的元素不从列表中删除。
  • addFirst()addLast() :将元素添加至首位跟末尾,若是列表已满,则会抛出IllegalStateException

能够看出无论是从获取仍是插入元素,都多了很多“花样”,其差异就在因而否阻塞,不知足条件是否返回null,不知足条件是否抛异常这几个方面来区分。安全

优先级排序阻塞式安全列表 - PriorityBlockingQueue

相信你们都写过把某个列表元素按照特定的规则来排序之类的代码,在PriorityBlockingQueue中,存放进去的元素必需要实现Comparable接口。在这个接口中,有一个compareTo()方法,当执行该方法的对象跟参数传入的对象进行比较的时候,这个方法会返回一个数字值,若是值小于0,则当前对象小于参数传入对象。大于0则相反,等于0就表示两个对象相等。markdown

public class DemoObj implements Comparable<DemoObj> {
   
    private int priority;
    
    @Override
    public int compareTo(DemoObj do){
        if(this.getPriority() > do.getPriority()){
            return -1;
        }else if(this.getPriority() < do.getPriority()){
            return 1;
        }
        return 0;
    }
    
    //省略getset ...
}


//==== use ===================

PriorityBlockingQueue<DemoObj> queue = new PriorityBlockingQueue()<>;
queue.put(DemoObj);
queue.peek();
复制代码

其经常使用方法跟上面提到的类基本都差很少你们能够动手实现一下,简单对比的话,能够说是LinkedBlockingDeque的加强版,多了元素排序功能。多线程

延迟元素线程安全列表 - DelayQueue

DelayQueue 里面存放着带有日期的元素,当咱们从列表获取数据的时候,未到时间的元素将会被忽略。所以,存放进来的元素必须实现Delayed接口,使之成为一个延迟对象。并发

/** * compareTo方法与getDelay方法需排序一致 */
class Order implements Delayed{

    private String name ;
    private long start = System.currentTimeMillis();
    private long time ;

    public MyDelayedTask(String name,long time) {
        this.name = name;
        this.time = time;
    }

    /** * 须要实现的接口,得到延迟时间 用过时时间-当前时间 * @param unit * @return */
    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert((start+time) - System.currentTimeMillis(),TimeUnit.MILLISECONDS);
    }

    /** * 延迟队列内部排序 当前对象延迟时间 - 入参对象的延迟时间 * @param o * @return */
    @Override
    public int compareTo(Delayed o) {
        Order o1 = (Order) o;
        return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o1.getDelay(TimeUnit.MILLISECONDS));
    }
}
复制代码

使用方式以下框架

private static DelayQueue delayQueue  = new DelayQueue();
    public static void main(String[] args) throws InterruptedException {

        new Thread(new Runnable() {
            @Override
            public void run() {

                delayQueue.offer(new Order("t3000",3000));
                delayQueue.offer(new Order("t4000",4000));
                delayQueue.offer(new Order("t2000",2000));
                delayQueue.offer(new Order("t6000",6000));
                delayQueue.offer(new Order("t1000",1000));

            }
        }).start();

        while (true) {
            Delayed take = delayQueue.take();
        }
    }
复制代码

关于结果的输出你们能够动手尝试一下~ide

结语

这里仅仅是介绍了几种经常使用的并发集合,其目的主要是让你们对这些集合有一个直观的认识,在使用的时候能够思考下本身的场景用哪一种更合适,若是当前介绍的类没合适的,那么是否还有其余并发集合会更有用呢?这里就当作抛砖引玉吧,有兴趣的朋友能够多去了解一下相关技术,相信你会有很多收获的。oop


公众号博文同步Github仓库,有兴趣的朋友能够帮忙给个Star哦,码字不易,感谢支持。

github.com/PeppaLittle…

推荐阅读

如何优化代码中大量的if/else,switch/case?
如何提升使用Java反射的效率?
Java日志正确使用姿式

有收获的话,就点个赞吧

关注「深夜里的程序猿」,分享最干的干货

相关文章
相关标签/搜索