Java多线程技术9——非阻塞队列

news2024/10/6 10:28:11

1 概述

        非阻塞队列的特色是队列里面没有数据时,返回异常或null。在JDK的并发包中,常见的非阻塞队列有:ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、ConcurrentLinkedQueue、ConcurrentLinkedDeque、CopyOnWriteArrayList、CopyOnWriteArraySet。本篇将介绍这7个非阻塞队列的特点与使用。

2 ConcurrentHashMap类的使用

2.1 验证HashMap不是线程安全的

public class MyService1 {
    public HashMap map = new HashMap();

    public void testMethod(){
        for (int i = 0; i < 5000; i++) {
            map.put(Thread.currentThread().getName()+" " + (i+1),Thread.currentThread().getName()+" " + (i+1));
            System.out.println(Thread.currentThread().getName() + " " + (i+1));
        }
    }
}
public class Thread1 extends Thread{
    private MyService1 service1;

    public Thread1(MyService1 service1) {
        this.service1 = service1;
    }
    @Override
    public void run(){
        service1.testMethod();
    }
}
public class Thread2 extends Thread{
    private MyService1 service1;

    public Thread2(MyService1 service1) {
        this.service1 = service1;
    }

    @Override
    public void run(){
        service1.testMethod();
    }
}
public class Run1 {
    public static void main(String[] args) {
        MyService1 service1 = new MyService1();
        Thread1 t1 = new Thread1(service1);
        t1.start();
    }
}

如果只创建一个线程Thread1,那么运行结果是正确的。此时控制台运行结果是:

在创建一个线程Thread2,运行结果是:

public class Run1 {
    public static void main(String[] args) {
        MyService1 service1 = new MyService1();
        Thread1 t1 = new Thread1(service1);
        Thread2 t2 = new Thread2(service1);
        t1.start();
        t2.start();
    }
}

        程序运行后会有很小的概率出现异常(笔者试了很多次没有出现-_-||,读者请自行实验),说明hashMap不能被多个线程操作,也就证明HashMap是非线程安全的。

2.2 验证HashTable是线程安全的

public class MyService1 {
    public Hashtable hashtable = new Hashtable();
    public void method(){
        for (int i = 0; i < 50000; i++) {
            hashtable.put(Thread.currentThread().getName()+ " "+(i+1),
                    Thread.currentThread().getName()+ " "+(i+1));
            System.out.println(Thread.currentThread().getName() + " " + (i+1));
        }
    }
}
public class Thread2 extends Thread{
    private MyService1 service1;

    public Thread2(MyService1 service1) {
        this.service1 = service1;
    }

    @Override
    public void run(){
        service1.method();
    }
}
public class Thread1 extends Thread{
    private MyService1 service1;

    public Thread1(MyService1 service1) {
        this.service1 = service1;
    }
    @Override
    public void run(){
        service1.method();

    }
}
public class Run1 {
    public static void main(String[] args) {
        MyService1 service1 = new MyService1();
        Thread1 t1 = new Thread1(service1);
        Thread1 t2 = new Thread1(service1);
        t1.start();
        t2.start();
    }
}

        

        程序运行正确,证明HashTable类在多线程环境中执行put操作不会出错,是线程安全的类。但是,多个线程分别调用该类的iteartor()方法返回Iterator对象,并调用next()方法取得元素,再执行remove()方法时会出现修改并发修改异常,说明HashTable不支持Iterator并发删除。

2.3 验证ConcurrentHashMap线程安全

        ConcurrentHashMap类是JDK并发包中提供的支持并发操作的Map对象。其继承与实现信息如下:

public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
    implements ConcurrentMap<K,V>, Serializable {
    private static final long serialVersionUID = 7249069246763182397L;
}

        下面开始验证: 

public class MyService1 {
    public ConcurrentHashMap map = new ConcurrentHashMap();
    public void method(){
        for (int i = 0; i < 50000; i++) {
            map.put(Thread.currentThread().getName()+ " "+(i+1),
                    Thread.currentThread().getName()+ " "+(i+1));
            System.out.println(Thread.currentThread().getName() + " " + (i+1));
        }
    }
}
public class Thread2 extends Thread{
    private MyService1 service1;

    public Thread2(MyService1 service1) {
        this.service1 = service1;
    }

    @Override
    public void run(){
        service1.method();
    }
}
public class Thread1 extends Thread{
    private MyService1 service1;

    public Thread1(MyService1 service1) {
        this.service1 = service1;
    }
    @Override
    public void run(){
        service1.method();

    }
}
public class Run1 {
    public static void main(String[] args) {
        MyService1 service1 = new MyService1();
        Thread1 t1 = new Thread1(service1);
        Thread1 t2 = new Thread1(service1);
        t1.start();
        t2.start();
    }
}

2.4 验证ConcurrentHashMap并发删除

public class MyService2 {
    public ConcurrentHashMap map = new ConcurrentHashMap();

    public MyService2() {
        for (int i = 0; i < 50000; i++) {
            map.put(Thread.currentThread().getName() + (i+1),"abc");
        }
    }

    public void test(){
        Iterator iterator = map.keySet().iterator();
        while(iterator.hasNext()){
            Object next = iterator.next();
            iterator.remove();
            System.out.println(map.size() + " " + Thread.currentThread().getName());
        }
    }
}
public class Thread1 extends Thread{
    public MyService2 myService2;

    public Thread1(MyService2 myService2) {
        this.myService2 = myService2;
    }
    @Override
    public void run(){
        myService2.test();
    }
}
public class Thread2 extends Thread{
    public MyService2 service2;

    public Thread2(MyService2 service2) {
        this.service2 = service2;
    }

    @Override
    public void run(){
        service2.test();
    }
}
public class Run2 {
    public static void main(String[] args) {
        MyService2 myService2 = new MyService2();
        Thread1 t1 = new Thread1(myService2);
        Thread2 t2 = new Thread2(myService2);
        t1.start();
        t2.start();

    }
}

         

        从运行结果看,ConcurrentHashMap在并发情况下支持put和remove。ConcurrentHashMap不支持排序,LinkedHashMap支持key排序,但不支持并发。如果出现既要求并发又要求排序的情况,就可以使用ConcurrentSkipListMap类。

3 ConcurrentSkipListMap类的使用

        ConcurrentSkipListMap支持排序。

public class UserInfo implements Comparable<UserInfo>{
    private int id;
    private String username;

    public UserInfo(int id, String username) {
        this.id = id;
        this.username = username;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }


    @Override
    public int compareTo(UserInfo o) {
        if(this.getId() > o.getId()){
            return 1;
        }else{
            return -1;
        }
    }
}
public class MyService {
    public ConcurrentSkipListMap<UserInfo,String> map = new ConcurrentSkipListMap<>();
    public MyService(){
        UserInfo userInfo1 = new UserInfo(1,"userinfo1");
        UserInfo userInfo3 = new UserInfo(3,"userinfo1");
        UserInfo userInfo5 = new UserInfo(5,"userinfo1");
        UserInfo userInfo2 = new UserInfo(2,"userinfo1");
        UserInfo userInfo4 = new UserInfo(4,"userinfo1");
        map.put(userInfo1,"u1");
        map.put(userInfo3,"u3");
        map.put(userInfo5,"u5");
        map.put(userInfo2,"u2");
        map.put(userInfo4,"u4");
    }

    public void method(){
        Map.Entry<UserInfo, String> entry = map.pollFirstEntry();
        System.out.println("map size() = " + map.size());
        UserInfo userInfo = entry.getKey();
        System.out.println(userInfo.getId() + " " + userInfo.getUsername() + " " + map.get(userInfo) + " " +entry.getValue());
    }
}
public class MyThread extends Thread{
    private MyService service;

    public MyThread(MyService service) {
        this.service = service;
    }

    @Override
    public void run(){
        service.method();
    }
}
public class Run1 {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        MyThread t1 = new MyThread(service);
        MyThread t2 = new MyThread(service);
        MyThread t3 = new MyThread(service);
        MyThread t4 = new MyThread(service);
        MyThread t5 = new MyThread(service);
        t1.start();
        Thread.sleep(1000);
        t2.start();
        Thread.sleep(1000);
        t3.start();
        Thread.sleep(1000);
        t4.start();
        Thread.sleep(1000);
        t5.start();

    }
}

        控制台打印出null的值是使用pollFirstEntry()方法将当前的Entry对象从类ConcurrentSkipListMap中删除造成的。

4 ConcurrentSkipListSet类的使用

         ConcurrentSkipListSet 类支持排序且不允许元素重复。

public class UserInfo implements Comparable<UserInfo> {
    private int id;
    private String username;

    public UserInfo(int id, String username) {
        this.id = id;
        this.username = username;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public int compareTo(UserInfo userInfo){
        if(this.getId() < userInfo.getId()){
            return -1;
        }
        if(this.getId() > userInfo.getId()){
            return 1;

        }
        return 0;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserInfo userInfo = (UserInfo) o;
        return id == userInfo.id && Objects.equals(username, userInfo.username);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, username);
    }
}
public class MyService {
    public ConcurrentSkipListSet set = new ConcurrentSkipListSet();
    public MyService(){
        UserInfo userInfo1 = new UserInfo(1,"username1");
        UserInfo userInfo3 = new UserInfo(3,"username3");
        UserInfo userInfo5 = new UserInfo(5,"username5");
        UserInfo userInfo41 = new UserInfo(4,"username4");
        UserInfo userInfo42 = new UserInfo(4,"username4");
        UserInfo userInfo2 = new UserInfo(2,"username2");
        set.add(userInfo1);
        set.add(userInfo3);
        set.add(userInfo5);
        set.add(userInfo41);
        set.add(userInfo42);
        set.add(userInfo2);
    }
}
public class MyThread extends Thread{
    private MyService service;

    public MyThread(MyService service) {
        this.service = service;
    }

    @Override
    public void run(){
        UserInfo userInfo = (UserInfo) service.set.pollFirst();
        System.out.println(userInfo.getId() + " " + userInfo.getUsername());
    }
}
public class Run1 {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        MyThread t1 = new MyThread(service);
        MyThread t2 = new MyThread(service);
        MyThread t3 = new MyThread(service);
        MyThread t4 = new MyThread(service);
        MyThread t5 = new MyThread(service);
        t1.start();
        Thread.sleep(1000);
        t2.start();
        Thread.sleep(1000);
        t3.start();
        Thread.sleep(1000);
        t4.start();
        Thread.sleep(1000);
        t5.start();
    }
}

        从运行结果可以看到,排序成功,并且不支持数据重复。 

5 ConcurrentLinkedQueue类的使用

        ConcurrentLinkedQueue类提供了并发环境下的队列操作。

public class MyService {
    public ConcurrentLinkedDeque queue = new ConcurrentLinkedDeque();
}
public class ThreadA extends Thread{
    private MyService service;

    public ThreadA(MyService service) {
        this.service = service;
    }

    @Override
    public void run(){
        for (int i = 0; i < 50; i++) {
            service.queue.add("threadA" + (i +1));
        }
    }
}
public class ThreadB extends Thread{
    private MyService service;

    public ThreadB(MyService service) {
        this.service = service;
    }

    @Override
    public void run(){
        for (int i = 0; i < 50; i++) {
            service.queue.add("ThreadB"+ (i+1));
        }
    }
}
public class Run1 {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        ThreadA a = new ThreadA(service);
        ThreadB b = new ThreadB(service);
        a.start();
        b.start();
        a.join();
        b.join();
        System.out.println(service.queue.size());
    }
}

         

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1352288.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录算法训练营Day16 | 654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树

LeetCode 654 最大二叉树 本题思路&#xff1a;我们可以看到每次其实这个找最大值&#xff0c;然后创建节点的过程就是一个二叉树的前序遍历的过程。所以&#xff0c;我们可以递归来完成它。 先创找到数组中&#xff0c;最大的值的下标&#xff0c;然后创建根节点然后根据下标…

Jmeter二次开发实操问题汇总(JDK问题,jar包问题)

前提 之前写过一篇文章&#xff1a;https://qa-lsq.blog.csdn.net/article/details/119782694 只是简单尝试了一下生成一个随机手机号码。 但是如果在工作中一个实际场景要用的二次开发&#xff0c;可能会遇到一些问题。 比如这样一个场景&#xff1a; Mobile或者前端调用部分…

【数据结构】堆的实现及TOP-K问题

文章目录 前言1. 堆的概念及结构2. 堆的实现2.1 堆向上调整算法2.2 堆向下调整算法2.3 堆的创建2.4 堆的删除2.5 堆的常用接口代码实现 3. 堆的应用TOP-K问题 前言 在正式讲堆之前&#xff0c;我们要先来讲一下二叉树的顺序结构&#xff1a; 普通的二叉树是不适合用数组来存储…

Python 实现给 pdf 文件自动识别标题并增添大纲

一、背景&#xff1a; 客户方提供过来一个开放平台的pdf文档&#xff0c;文档里有几十个接口&#xff0c;没有大纲和目录可以定位到具体内容&#xff0c;了解整体的API功能&#xff0c;观看体验极度差劲&#xff0c;所以想使用Python代码自动解析pdf文档&#xff0c;给文档增添…

AntDB设计之CheckPoint——引言与功能简述

1.引言 数据库服务能力提升是一项系统性的工程&#xff0c;在不同的应用场景下&#xff0c;用户对于数据库各项能力的关注点也不同&#xff0c;如&#xff1a;读写延迟、吞吐量、扩展性、可靠性、可用性等等。国内不少数据库系统通过系统架构优化、硬件设备升级等方式&#xf…

【单片机 TB作品】节拍器,电子音乐节拍器,51单片机,Proteus仿真

节拍器的使用可以使练琴者正确掌握乐曲的速度,从而使音 乐练习达到事半功倍的效果。本课题基于单片机设计具有声光晋 示的电子乐器节拍器,充分利用单片机的定时和中断系统,通过 C语言程序设计,控制外部相关硬件电路,实现对音乐速,度 40~120次/分钟范围内连续可调,节拍114、 2/4…

Redis命令---Hash(哈希)篇 (超全)

目录 1.Redis Hmset 命令 - 同时将多个 field-value (域-值)对设置到哈希表 key 中。简介语法可用版本: > 2.0.0返回值: 如果命令执行成功&#xff0c;返回 OK 。 示例 2.Redis Hmget 命令 - 获取所有给定字段的值简介语法可用版本: > 2.0.0返回值: 一个包含多个给定字段…

Simple Facebook Sign-In

简单的Facebook登录为Android、iOS、Windows、Mac、通用Windows平台(UWP)和Unity制作的WebGL应用程序提供了基于OAuth 2.0的Facebook登录。 优点: ● 跨平台游戏和应用程序的跨平台用户身份验证 ● 无插件,无第三方库,无依赖● 对建筑规模没有影响 ● 客户端-服务器应…

PMP证书可以挂靠吗?

PMP证书不是国内的证书&#xff0c;挂靠不了呀&#xff0c;想挂靠&#xff0c;可以考软考/一建等&#xff0c;里面也有项目管理相关的证书。 PMP证书虽然不能挂靠&#xff0c;但是用处还是很大的&#xff0c;例如提升个人能力、薪资待遇&#xff0c;还有持证可享一些城市的福利…

kafka容灾演练的方案

背景 kafka可以通过MirrorMaker工具把集群的数据从一个集群同步到另一个集群&#xff0c;通过在另一个数据中心创建灾备集群的方式可以做到容灾的效果,但是如果我们不通过如此重量级的工具也想达到容灾演练的目的&#xff0c;可以怎么做呢 kafka简单容灾实现 当原kafka集群发…

计算机网络--作业

作业一 1、比较电路交换、报文交换和分组报文交换优缺点 电路交换 电路交换是以电路连接为目的的交换方式&#xff0c;通信之前要在通信双方之间建立一条被双方独占的物理通道&#xff08;由通信双方之间的交换设备和链路逐段连接而成&#xff09;。 优点&#xff1a; ①由于…

MyBatis学习一:快速入门

前言 公司要求没办法&#xff0c;前端也要了解一下后端知识&#xff0c;这里记录一下自己的学习 学习教程&#xff1a;黑马mybatis教程全套视频教程&#xff0c;2天Mybatis框架从入门到精通 文档&#xff1a; https://mybatis.net.cn/index.html MyBatis 快速入门&#xf…

HackTheBox - Medium - Linux - Bagel

Bagel 今天我开始了《Red Team Development and Operations A Practical Guide》的学习&#xff0c;保持学习&#xff0c;后面差不多到时机后就学CRTOⅡ Bagel 是一款中等难度的 Linux 机器&#xff0c;其特点是电子商店容易受到路径遍历攻击&#xff0c;通过该攻击可以获取应…

Tinker 环境下数据表的用法

如果我们要自己手动创建一个模型文件&#xff0c;最简单的方式是通过 make:model 来创建。 php artisan make:model Article 删除模型文件 rm app/Models/Article.php 创建模型的同时顺便创建数据库迁移 php artisan make:model Article -m Eloquent 表命名约定 在该文件中&am…

k8s中实现pod自动扩缩容

一、k8s应用自动扩缩容概述 1&#xff09;背景&#xff1a; 在实际的业务场景中&#xff0c;我们经常会遇到某个服务需要扩容的场景&#xff08;例如&#xff1a;测试对服务压测、电商平台秒杀、大促活动、或由于资源紧张、工作负载降低等都需要对服务实例数进行扩缩容操作&…

SD-WAN组网方式详解

企业网络的演进势不可挡&#xff0c;对于高效、可靠的网络连接需求日益增加。SD-WAN&#xff08;软件定义广域网&#xff09;作为一项创新的网络技术&#xff0c;备受企业青睐并得到广泛应用。SD-WAN提供了多种灵活的组网方式&#xff0c;以满足企业多样化的需求和不同的网络环…

AI实景无人直播创业项目:开启自动直播新时代,一部手机即可实现财富增长

在当今社会&#xff0c;直播已经成为了人们日常生活中不可或缺的一部分。无论是商家推广产品、明星互动粉丝还是普通人分享生活&#xff0c;直播已经渗透到了各行各业。然而&#xff0c;传统直播方式存在着一些不足之处&#xff0c;如需现场主持人操作、高昂的费用等。近年来&a…

亚信安慧AntDB数据库引领数字时代:数字驱动创新峰会主旨演讲深度解析

近日&#xff0c;庄严肃穆的数字驱动创新峰会在中国首都北京隆重召开&#xff0c;聚焦于探讨数据经济的创新前沿。在此次盛会中&#xff0c;备受瞩目的亚信安慧AntDB数据库荣幸受邀参与&#xff0c;该数据库的副总裁张桦以其深刻见解和卓越经验发表了引人瞩目的主旨演讲。 图1&…

立体匹配算法(Stereo correspondence)

SGM(Semi-Global Matching)原理&#xff1a; SGM的原理在wiki百科和matlab官网上有比较详细的解释&#xff1a; wiki matlab 如果想完全了解原理还是建议看原论文 paper&#xff08;我就不看了&#xff0c;懒癌犯了。&#xff09; 优质论文解读和代码实现 一位大神自己用c实现…

系列九、Feign

一、Feign 1.1、Java中如何实现跨接口调用 &#xff08;1&#xff09; Httpclient Httpclient是Apache Jakarta Comon下的子项目&#xff0c;用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包&#xff0c;并且它支持HTTP协议的最新版本和建议。HttpC…