【多线程(六)】并发工具类的基本使用、ConcurrentHashMap1.7版本及1.8版本底层原理分析

news2025/1/12 1:42:10

文章目录

  • 6.并发工具类
    • 6.1 并发工具类-Hashtable
    • 6.2 并发工具类-ConcurrentHashMap基本使用
    • 6.3 并发工具类-ConcurrentHashMap1.7原理
    • 6.4 并发工具类-ConcurrentHashMap1.8原理
    • 6.5 并发工具类-CountDownLatch
    • 6.6并发工具类-Semaphore
    • 总结

6.并发工具类

6.1 并发工具类-Hashtable

  • Hashtable出现的原因:在集合类中HashMap是比较常用的集合对象,但是HashMap是线程不安全的(多线程环境下可能会存在问题)。为了保证数据的安全性我们可以使用Hashtable,但是Hashtable的效率低下
  • 代码实现
package com.hcx.mymap;

import java.util.HashMap;
import java.util.Hashtable;

public class MyHashtableDemo {
    public static void main(String[] args) throws InterruptedException {
        Hashtable<String,String> hm = new Hashtable<>();

        Thread t1 = new Thread(()->{
            for (int i = 0; i < 25; i++) {
                hm.put(i+" ",i+" ");
                
            }
        });

        Thread t2 = new Thread(()->{
            for (int i = 25; i < 51; i++) {
                hm.put(i+" ",i+" ");

            }
        });

        t1.start();
        t2.start();

        System.out.println("=============");
        //让 main 线程睡一秒中,为了让 t1、t2能把数据全部添加完毕
        Thread.sleep(1000);

        for (int i = 0; i < 51; i++) {

            System.out.println(hm.get(i+" "));

        }//0 1 2 3 4 ... 50

    }
}

  • 运行结果
    在这里插入图片描述

6.2 并发工具类-ConcurrentHashMap基本使用

  • ConcurrentHashMap出现的原因:在集合中HashMap是比较常用的集合对象,但是HashMap是线程不安全的(多线程环境下可能会存在问题)。为了保证数据的安全性我们可以使用Hashtable,但是Hashtable的效率低下。基于以上两个原因我们可以使用JDK1.5以后所提供的ConcurrentHashMap。

  • 体系结构
    在这里插入图片描述

  • 总结

    • 1.HashMap是线程不安全的 ,多线程环境下会有数据安全问题。
    • 2.Hashtable是线程安全的,但是会将整张表锁起来,效率低下
    • 3.ConcurrentHashMap也是线程安全的,效率较高,在JDK7和JDK8中,底层原理不一样。
  • 代码实现

package com.hcx.mymap;

import java.util.Hashtable;
import java.util.concurrent.ConcurrentHashMap;

public class MyConcurrentHashMapDemo {
    public static void main(String[] args) throws InterruptedException {
        ConcurrentHashMap<String,String> hm = new ConcurrentHashMap<>();

        Thread t1 = new Thread(()->{
            for (int i = 0; i < 25; i++) {
                hm.put(i+" ",i+" ");
                
            }
        });

        Thread t2 = new Thread(()->{
            for (int i = 25; i < 51; i++) {
                hm.put(i+" ",i+" ");

            }
        });

        t1.start();
        t2.start();

        System.out.println("=============");
        //让 main 线程睡一秒中,为了让 t1、t2能把数据全部添加完毕
        Thread.sleep(1000);

        for (int i = 0; i < 51; i++) {

            System.out.println(hm.get(i+" "));

        }//0 1 2 3 4 ... 50

    }
}

  • 运行结果
    在这里插入图片描述

6.3 并发工具类-ConcurrentHashMap1.7原理

在这里插入图片描述

  • 创建对象
    • 1.默认创建一个长度16,加载因子为0.75的大数组。
    • 2.还会创建一个长度为2的小数组,把地址值赋值给0索引处,其他索引位置的元素都是null
  • 添加数据
    • 为 null:
      • 则按照模板创建小数组,创建完毕,会二次哈希,计算出在小数组中应存入的位置,直接存入。
    • 如果不为null:
      • 就会根据记录的地址值找到小数组 ,二次哈希,计算出在小数组中应存入的位置。如果要扩容,则将小数组扩容两倍,如果不需要扩容,则就会判断小数组这个位置有没有元素,如果没有元素,则直接存,如果有元素,就会调用equals方法,比较属性值,如果equals为true,则不存,如果equals为false,形成哈希桶结构

6.4 并发工具类-ConcurrentHashMap1.8原理

在这里插入图片描述

  • 总结
    • 1,如果使用空参构造创建ConcurrentHashMap对象,则什么事情都不做。 在第一次添加元素的时候创建哈希表。
    • 2,计算当前元素应存入的索引。
    • 3,如果该索引位置为null,则利用cas算法,将本结点添加到数组中。
    • 4,如果该索引位置不为null,则利用volatile关键字获得当前位置最新的结点地址,挂在他下面,变成链表。
    • 5,当链表的长度大于等于8时,自动转换成红黑树6,以链表或者红黑树头结点为锁对象,配合悲观锁保证多线程
      操作集合时数据的安全性。

6.5 并发工具类-CountDownLatch

  • CountDownLatch类
    在这里插入图片描述

  • 使用场景:让某一条线程等待其他线程执行完毕之后再执行。

  • 代码实现

package com.hcx.mycountdownlatch;

import java.util.concurrent.CountDownLatch;

public class ChildThread1 extends Thread {
    private CountDownLatch countDownLatch;
    public ChildThread1(CountDownLatch countDownLatch) {
        this.countDownLatch=countDownLatch;
    }
    @Override
    public void run() {
        //1.吃饺子
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+"在吃第"+ i+ "个饺子");
        }
        //吃完说一声
        //每一次countDown方法的时候,就让计数器减1
        countDownLatch.countDown();

    }
}

package com.hcx.mycountdownlatch;

import java.util.concurrent.CountDownLatch;

public class ChildThread2 extends Thread {
    private CountDownLatch countDownLatch;
    public ChildThread2(CountDownLatch countDownLatch) {
        this.countDownLatch=countDownLatch;
    }
    @Override
    public void run() {
        for (int i = 0; i < 15; i++) {
            System.out.println(getName()+"在吃第"+ i+ "个饺子");
        }
        //吃完说一声
        countDownLatch.countDown();

    }
}
package com.hcx.mycountdownlatch;

import java.util.concurrent.CountDownLatch;

public class ChildThread3 extends Thread {
    private CountDownLatch countDownLatch;
    public ChildThread3(CountDownLatch countDownLatch) {
        this.countDownLatch=countDownLatch;
    }
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(getName()+"在吃第"+ i+ "个饺子");
        }
        //吃完说一声
        countDownLatch.countDown();

    }
}

package com.hcx.mycountdownlatch;

import java.util.concurrent.CountDownLatch;

public class MotherThread extends Thread {
    private CountDownLatch countDownLatch;
    public MotherThread(CountDownLatch countDownLatch) {
        this.countDownLatch=countDownLatch;
    }

    @Override
    public void run() {
        //1.等待
        try {
            //当计数器变成0的时候,会自动唤醒这里等待的线程。
            countDownLatch.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //2.收拾碗筷
        System.out.println("妈妈在收拾碗筷");

    }
}

package com.hcx.mycountdownlatch;

import java.util.concurrent.CountDownLatch;

public class MyCountDownLatchDemo {
    public static void main(String[] args) {
        //1.创建 CountDownLatch的对象,需要传递给四个线程
        //在底层就定义了一个计数器,此时计数器的值就是3
        CountDownLatch countDownLatch = new CountDownLatch(3);//参数传递的是等待线程的数量

        //2.创建四个线程线程对象并开启他们
        MotherThread motherThread = new MotherThread(countDownLatch);
        motherThread.start();

        ChildThread1 t1 = new ChildThread1(countDownLatch);
        t1.setName("小明");

        ChildThread2 t2 = new ChildThread2(countDownLatch);
        t2.setName("小红");

        ChildThread3 t3 = new ChildThread3(countDownLatch);
        t3.setName("小刚");

        t1.start();
        t2.start();
        t3.start();


    }
}

  • 总结
      1. CountDownLatch(int count):参数写等待线程的数量。并定义了一个计数器。
      1. await():让线程等待,当计数器为0时,会唤醒等待的线程
      1. countDown(): 线程执行完毕时调用,会将计数器-1。

6.6并发工具类-Semaphore

  • 使用场景

    • 可以控制访问特定资源的线程数量。
  • 实现步骤

    • 1,需要有人管理这个通道
    • 2,当有车进来了,发通行许可证
    • 3,当车出去了,收回通行许可证
    • 4,如果通行许可证发完了,那么其他车辆只能等着
  • 代码实现

package com.hcx.mysemaphore;

import java.util.concurrent.Semaphore;

public class MyRunnable implements  Runnable {
    //1.获得管理员对象,
    private Semaphore semaphore = new Semaphore(2);//参数为最多允许几个线程同时进行
    @Override
    public void run() {
        //2.获得通行证
        try {
            semaphore.acquire();//如果线程没有获得通行证,则会一直在这里等着,直到获得通行证为止
            //3.开始行驶
            System.out.println("获得了通行证开始行驶");
            Thread.sleep(2000);
            System.out.println("归还通行证");
             semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //4.归还通行证
    }
}

package com.hcx.mysemaphore;

public class MySemaphoreDemo {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        for (int i = 0; i < 100; i++) {
            Thread thread = new Thread(myRunnable);
            thread.start();
        }
    }
}
  • 运行结果
    在这里插入图片描述

总结

本篇文章介绍了并发工具类 Hashtable、ConcurrentHashMap、 CountDownLatch、Semaphore的基本使用,并讲解了ConcurrentHashMap1.7版本以及1.8版本的底层原理。希望大家多多支持!在这里插入图片描述

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

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

相关文章

一文看懂MySQL中order by排序语句的原理

order by 是怎么工作的&#xff1f; 表定义 CREATE TABLE t1 ( id int(11) NOT NULL, city varchar(16) NOT NULL, name varchar(16) NOT NULL, age int(11) NOT NULL, addr varchar(128) DEFAULT NULL, PRIMARY KEY (id), KEY city (city)) ENGINEInnoDB;SQL语句可以…

零基础入门JavaWeb——Vue的生命周期

一、概念 在编程领域&#xff0c;生命周期是一个很常见的概念。一个对象从创建、初始化、工作、释放、清理和销毁&#xff0c;会经历很多环节的演变。 二、Vue对象的生命周期 三、生命周期钩子函数 Vue允许在特定的生命周期环节中通过钩子函数加入我们的代码。 3.1 示例代码…

基于双向LSTM模型进行电力需求预测(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f389;作者研究&#xff1a;&#x1f3c5;&#x1f3c5;&#x1f3c5;主要研究方向是电力系统和智能算法、机器学…

尚硅谷笔记——求和案例纯react版、redux精简版

家人们天气冷啦注意保暖呀&#xff0c;不要像我一样因为冷而不想起床学习&#xff0c;冬日里也不能放弃训练 看了两遍尚硅谷的redux课程&#xff0c;把reduc案例代码重新敲了一次为了加深印象还是写个播客把&#xff0c;强烈推荐大家看尚硅谷课太细致啦 redux 是什么&#x…

即将到来的2023,国内元宇宙开始“割”企业了?

元宇宙爆火一年后&#xff0c;UTONMOS即将成为全球化全部实现ERC-721协议NFT链上垂直游戏价值生态的系统平台&#xff0c;旨在通过利用自身所拥有的各类头部资源和游戏化打造内容层的融合&#xff0c;建立一个元气满满的元宇宙Web3.0平台。 通过数字藏品技术的应用&#xff0c…

Flask框架

Flask一 前言二 快速使用三 内置配置变量四 配置文件的写法五 路由六 cbv写法6.1 快速使用6.2 cbv加装饰器6.3 as_view的执行流程6.4 as_view的name参数6.5 继承View写cbv七 模板语法7.1 渲染变量7.2 变量的循环7.3 逻辑判断一 前言 Flask是一个基于Python开发并且依赖jinja2模…

Fluent中模型设置和数据的复用

1 背景 在实际工程中&#xff0c;必然存在利用仿真比较各类设计方案优劣的场景。 对于复杂模型&#xff0c;逐个设置各个设计方案的仿真模型并从头开始计算结果&#xff0c;既易错也耗时。因此需要通过模型设置和数据的复用&#xff0c;达到防错和提高工作效率。 2 模型设置复…

基于Docker做MySQL主从搭建与Django的读写分离

目录 基于Docker做MySQL主从搭建 django读写分离 基于Docker做MySQL主从搭建 主从的作用&#xff1a;写数据数据时使用主库&#xff0c;从库只用来读数据&#xff0c;这样做能够减少数据库压力&#xff0c;主从搭建可以一主一从&#xff0c;也可以是一主多从。 mysql主从配…

肝2022世界杯,怒写企业级镜像私仓Docker+Harbor实践

2022-12-09 揭幕2022卡塔尔世界杯4强角逐的第一天&#xff0c;越来越精彩了 同时记录程序猿的成长~ 1.背景 由于期望搭建一个企业级CICD的环境&#xff0c;开始尝试常规的gitlabjenkinsk8sdocker harborspringboot开始练手 其中版本如下&#xff1a; 1.gitlab: GitLab Com…

天权信安catf1ag网络安全联合公开赛---wp

文章目录misc简单隐写十位马WebhistoryCrypto疑惑ezrsapasswdre遗失的物品misc 简单隐写 丢进kali binwalk 分离一下 得到一个加密的压缩包 内含flag.txt 使用jphs无密码得到一个txt 得到password:catf1agcatf1agcatf1ag 解压压缩包得到一串字符串 dbug1bh{KQit_x1o_Z0v_…

threejs官方demo学习(2):相机

webgl_camera 不知道是哪里写的有问题&#xff0c;最终的效果&#xff0c;跟官方案例有比较大的差距。不过可以学到的知识点挺多的。 知识点 CameraHelper 相机辅助对象&#xff0c;用于模拟相机视锥体 // 创建透视相机 cameraPerspective new THREE.PerspectiveCamera(5…

二叉树路径和(c#)

问题描述 给定一个二叉树的根和一个整数值&#xff0c;如果二叉树中有根节点到叶子节点的路径上节点值的和等于给定的整数值&#xff0c;则返回真&#xff0c;否则返回假。 叶子节点:没有孩子的节点。 示例 示例1 Input: root [5,4,8,11,null,13,4,7,2,null,null,null,1], t…

两个List<Integer>在相同的值比较返回值为false的问题解析

写在前面:今天刷LeetCode的时候发现一个测试用例始终过不去&#xff0c;代码出问题处大概表述如下: List<Integer> a new ArrayList<>(); a.add(300); List<Integer> b new ArrayList<>(); b.add(300); if(a.get(0) b.get(0)){ 代码块B } else{ 代…

[生成 pdf 详解]

目录 前言: pom需要的依赖: 测试类: 效果: 生成表格PDF: 其他复杂的格式就去研究那个 如何生成吧 测试类代码: 前言: 摸鱼来的 pom需要的依赖: <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><vers…

【计算机毕业设计】76.垃圾分类系统源码

一、系统截图&#xff08;需要演示视频可以私聊&#xff09; 摘 要 随着现在网络的快速发展&#xff0c;网上管理系统也逐渐快速发展起来&#xff0c;网上管理模式很快融入到了许多国有企业的之中&#xff0c;随之就产生了“垃圾分类系统”&#xff0c;这样就让垃圾分类系统更…

web前端大作业:旅游网页主题网站设计——武汉旅游网页设计(11页)HTML+CSS+JavaScript

&#x1f468;‍&#x1f393;学生HTML静态网页基础水平制作&#x1f469;‍&#x1f393;&#xff0c;页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码&#xff0c;这是一个不错的旅游网页制作&#xff0c;画面精明&#xff0c;排版整洁&#xff0c;内容…

AWS CodeCommit SSH公钥配置

在本地计算机上的终端中&#xff0c;运行 ssh-keygen 命令&#xff0c;并按照说明将文件保存到您的配置文件的 .ssh 目录中。 其中windows用户可以使用git bash。 这会生成&#xff1a; codecommit_rsa 文件&#xff0c;该文件为私有密钥文件。 codecommit_rsa.pub 文件&#…

Android 搜索匹配的文字之后显示成红色

先简单看一下效果&#xff1a; 实现的主要代码&#xff1a; /*** * param color 需要提示的演示* param txt 字符串信息* param keyword 搜索的关键字* return*/ private SpannableString matchSearchText(int color, String txt, String keyword) {SpannableString spannableS…

基于springboot vue前后端分离的赛事疫情管理系统源码

开发工具&#xff1a;idea (eclipse) 环境&#xff1a;jdk1.8 mysql5.7&#xff0c; navcat 演示视频&#xff1a; 【java毕业设计】基于springboot vue前后端分离的赛事疫情管理系统源码许多年以前&#xff0c;人们在对数据进行统计和记录时候&#xff0c;使用的是纸和笔&…

抄袭、侵权、刷单,谁在洗地机的风口自乱了阵脚?

文|螳螂观察 作者| 陈淼 又一记法律重锤落下&#xff0c;追觅再次被敲在行业的耻辱柱上。 日前&#xff0c;添可和追觅的专利纠纷案迎来最新进展。根据裁定结果&#xff0c;追觅最终向宁波市中级人民法院作出承诺&#xff0c;于2022年10月30日起停止生产、销售四款涉案产品及…