聊聊Java里常用的并发集合

前言

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

正文

非阻塞式安全列表 - ConcurrentLinkedDeque

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

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

阻塞式安全列表 - LinkedBlockingDeque

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

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

可以看出不管是从获取还是插入元素,都多了不少“花样”,其差别就在于是否阻塞,不满足条件是否返回null,不满足条件是否抛异常这几个方面来区分。

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

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

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

关于结果的输出大家可以动手尝试一下~

结语

这里仅仅是介绍了几种常用的并发集合,其目的主要是让大家对这些集合有一个直观的认识,在使用的时候可以思考下自己的场景用哪种更合适,如果当前介绍的类没合适的,那么是否还有其他并发集合会更有用呢?这里就当做抛砖引玉吧,有兴趣的朋友可以多去了解一下相关技术,相信你会有不少收获的。



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

https://github.com/PeppaLittlePig/blog-wechat

推荐阅读

如何优化代码中大量的if/else,switch/case?

如何提高使用Java反射的效率?

Java日志正确使用姿势

有收获的话,就点个赞吧

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

原文地址:https://www.cnblogs.com/coding-night/p/10893410.html

时间: 2024-08-28 06:48:34

聊聊Java里常用的并发集合的相关文章

java 多线程 同步 观察者 并发集合的一个例子

//第一版 package com.hra.riskprice; import com.hra.riskprice.SysEnum.Factor_Type; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import javax.swing.text.html.HTMLDocument; import j

java里常用的redis客户端简介

Redis的各种语言客户端列表,请参见Redis Client.其中Java客户端在github上start最高的是Jedis和Redisson.Jedis提供了完整Redis命令,而Redisson有更多分布式的容器实现. 原文地址:https://www.cnblogs.com/shamo89/p/8794734.html

java中常用的并发工具类

· 1. 等待多线程完成的CountDownLatch 构造函数接收一个int类型的参数作为计数器,如果想等待N个点,就传入N.当调用CountDownLatch的countDown方法时,N就会减一,直至减为零.使用await方法等待,当N的值变为零,执行await的线程继续执行. public class CountDownTest { static CountDownLatch c = new CountDownLatch(2); static ExecutorService pool =

java开发常用工具类集合总结

转自:https://blog.csdn.net/wu1226419614/article/details/72673686 1)java正则表达式的匹配包括:邮箱,手机,姓名,昵称,身份证号,银行卡号等: 2)生成6位随机数: 3)对url中字符串进行编码和解码 4)获取客户端ip地址 5)获取系统当前时间 6)生成32位编码不含横线 7)生成MD5编码 8)通过身份证获取性别 9)通过身份证获取生日 10)通过身份证获取生日 11)手机号中间4位替换成星号 12)邮箱地址加星号 13)生成随

【Java】常用数据类型转换(BigDecimal、包装类、日期等)

新工作转到大数据方向,每天都要面对数据类型互相转换的工作,再加上先前面试发现这部分的知识盲点, 决定复习之余自己再写一套便捷的方法,以后会比较方便.(虽然公司有现成封装的类,里头还有些遗漏的地方,暂时不敢随便修改 ) 1. BigDecimal和基本类型之间的转换 现在蹲在银行里做项目,对数字的精准性要求较高.比起Java里常用的double.int这些数据类型,BigDecimal的好处在于能够设置你想要的精度. ① BigDecimal和字符串String类型 //字符串 → BigDeci

Java常用工具类集合

数据库连接工具类 仅仅获得连接对象 ConnDB.java package com.util; import java.sql.Connection; import java.sql.DriverManager; /** * 数据库连接工具类——仅仅获得连接对象 * */ public class ConnDB { private static Connection conn = null; private static final String DRIVER_NAME = "com.mysql

java - 并发集合 Vector、synchronizedCollection、CopyOnWriteArrayList之间的区别。

概要 JDK中提供ArrayList集合方便我们对集合内元素进行增删改查,但是ArrayList为了能够在单线程中快速进行操作其设计并不支持多线程进行操作.ArrayList在多线程环境下可能会产生java.util.ConcurrentModificationException异常.而对于我们需要在多线程下操作集合Jdk为我们内置了支持多线程操作的并发集合类供我们使用. Vector Vector始于JDK1.0版本而ArrayList始于JDK1.2版本.Vector对于每个对集合操作的方法

Java多线程 阻塞队列和并发集合

转载:大关的博客 Java多线程 阻塞队列和并发集合 本章主要探讨在多线程程序中与集合相关的内容.在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃.Java为多线程专门提供了特有的线程安全的集合类,通过下面的学习,您需要掌握这些集合的特点是什么,底层实现如何.在何时使用等问题. 3.1 BlockingQueue接口 java阻塞队列应用于生产者消费者模式.消息传递.并行任务执行和相关并发设计的大多数常见使用上下文. BlockingQueue在Queue接口基础上提供了额外

第一章 Java常用的并发类

注:本系列博客主要参考于<分布式Java应用:基础与实践>,林昊 著 1.常用的并发集合类 ConcurrentHashMap:线程安全的HashMap的实现 CopyOnWriteArrayList:线程安全且在读操作时无锁的ArrayList CopyOnWriteArraySet:基于CopyOnWriteArrayList,不添加重复元素 ArrayBlockingQueue:基于数组.先进先出.线程安全,可实现指定时间的阻塞读写,并且容量可以限制 LinkedBlockingQueu