Java学习教程,从入门到精通,Java ConcurrentHashMap语法知识点及案例代码(63)

Java ConcurrentHashMap语法知识点及案例代码

ConcurrentHashMap 是 Java 中一个非常重要的线程安全的哈希表实现,它允许并发访问和修改,并且性能相对较好。以下是 ConcurrentHashMap 的语法知识点以及一个带有详细注释的示例代码。

语法知识点

  1. 引入包

    import java.util.concurrent.ConcurrentHashMap;
    
  2. 创建对象

    ConcurrentHashMap<KeyType, ValueType> map = new ConcurrentHashMap<>();
    
  3. 基本方法

    • put(K key, V value):将一个键值对放入映射中。
    • get(Object key):根据键获取值。
    • remove(Object key):根据键移除键值对。
    • containsKey(Object key):检查映射中是否包含指定的键。
    • size():返回映射中的键值对数量。
    • isEmpty():检查映射是否为空。
    • forEach(BiConsumer<? super K, ? super V> action):对映射中的每个键值对执行给定的操作。
  4. 并发特性

    • ConcurrentHashMap 使用分段锁(Segment Locks)或更现代的 CAS(Compare-And-Swap)操作来实现并发性,从而允许多个线程同时读取和写入。
    • 它的内部实现复杂,但对外提供了简洁的接口。

示例代码

以下是一个简单的示例代码,展示了如何使用 ConcurrentHashMap 来存储和管理线程安全的键值对。

import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;

public class ConcurrentHashMapExample {

    public static void main(String[] args) {
        // 创建一个ConcurrentHashMap实例
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();

        // 使用put方法添加元素
        map.put("Apple", 1);
        map.put("Banana", 2);
        map.put("Orange", 3);

        // 使用get方法获取元素
        Integer value = map.get("Banana");
        System.out.println("Value for 'Banana': " + value);

        // 使用containsKey方法检查是否包含某个键
        boolean containsKey = map.containsKey("Apple");
        System.out.println("Map contains 'Apple': " + containsKey);

        // 使用remove方法移除元素
        map.remove("Orange");

        // 使用size方法获取元素数量
        int size = map.size();
        System.out.println("Size of the map: " + size);

        // 使用isEmpty方法检查是否为空
        boolean isEmpty = map.isEmpty();
        System.out.println("Is the map empty? " + isEmpty);

        // 使用forEach方法遍历所有元素
        System.out.println("Elements in the map:");
        map.forEach((key, value) -> {
            System.out.println("Key: " + key + ", Value: " + value);
        });

        // 模拟并发访问
        Runnable task = () -> {
            for (int i = 0; i < 10; i++) {
                String key = "Key" + i;
                map.put(key, i);
                System.out.println(Thread.currentThread().getName() + " added " + key + " with value " + i);
            }
        };

        // 创建并启动多个线程
        Thread thread1 = new Thread(task, "Thread-1");
        Thread thread2 = new Thread(task, "Thread-2");

        thread1.start();
        thread2.start();

        try {
            // 等待线程结束
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 最终的元素数量(可能大于初始数量,因为多线程添加)
        System.out.println("Final size of the map after concurrent operations: " + map.size());
    }
}

代码解释

  1. 创建 ConcurrentHashMap 实例

    ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
    
  2. 添加元素

    map.put("Apple", 1);
    map.put("Banana", 2);
    map.put("Orange", 3);
    
  3. 获取元素

    Integer value = map.get("Banana");
    
  4. 检查是否包含某个键

    boolean containsKey = map.containsKey("Apple");
    
  5. 移除元素

    map.remove("Orange");
    
  6. 获取元素数量

    int size = map.size();
    
  7. 检查是否为空

    boolean isEmpty = map.isEmpty();
    
  8. 遍历所有元素

    map.forEach((key, value) -> {
        System.out.println("Key: " + key + ", Value: " + value);
    });
    
  9. 模拟并发访问

    • 定义了一个 Runnable 任务,每个任务会向 ConcurrentHashMap 中添加一些键值对。
    • 创建并启动两个线程来执行这个任务。
    • 使用 join 方法等待两个线程执行完毕。
  10. 输出最终的元素数量

    System.out.println("Final size of the map after concurrent operations: " + map.size());
    

通过这些示例和解释,你应该能够掌握 ConcurrentHashMap 的基本用法和并发特性。希望这些信息对你有帮助!

以下是关于 ConcurrentHashMap 的几个具体案例,这些案例展示了在不同场景下如何使用 ConcurrentHashMap 来实现线程安全的键值对存储和访问。

案例一:用户访问计数器

在这个案例中,我们使用 ConcurrentHashMap 来实现一个用户访问计数器,用于统计不同用户的访问次数。

import java.util.concurrent.ConcurrentHashMap;

public class UserVisitCounter {
    // 使用ConcurrentHashMap存储用户访问次数
    private ConcurrentHashMap<String, Integer> userCounts = new ConcurrentHashMap<>();

    // 用户访问时调用此方法增加计数
    public void visit(String userId) {
        // 使用compute方法实现线程安全的计数更新
        userCounts.compute(userId, (key, value) -> (value == null) ? 1 : value + 1);
    }

    // 获取用户的访问次数
    public int getCount(String userId) {
        // 使用getOrDefault方法获取访问次数,如果未找到则返回0
        return userCounts.getOrDefault(userId, 0);
    }

    public static void main(String[] args) {
        UserVisitCounter counter = new UserVisitCounter();

        // 模拟多线程用户访问
        Runnable task = () -> {
            for (int i = 0; i < 10; i++) {
                String userId = "User" + (int) (Math.random() * 100);
                counter.visit(userId);
                System.out.println(Thread.currentThread().getName() + " visited " + userId + ", total count: " + counter.getCount(userId));
            }
        };

        // 创建并启动多个线程
        for (int i = 0; i < 5; i++) {
            new Thread(task).start();
        }
    }
}

案例二:缓存系统

在这个案例中,我们使用 ConcurrentHashMap 来实现一个简单的缓存系统,用于存储和访问缓存数据。

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

public class SimpleCache<K, V> {
    // 使用ConcurrentHashMap存储缓存数据
    private ConcurrentHashMap<K, CacheEntry<K, V>> cache = new ConcurrentHashMap<>();

    // 缓存项,包含值和过期时间
    private static class CacheEntry<K, V> {
        final V value;
        final long expireTime;

        CacheEntry(V value, long expireTime) {
            this.value = value;
            this.expireTime = expireTime;
        }

        boolean isExpired() {
            return System.currentTimeMillis() > expireTime;
        }
    }

    // 添加缓存项,指定过期时间
    public void put(K key, V value, long expireTime, TimeUnit timeUnit) {
        long expireTimeMillis = System.currentTimeMillis() + timeUnit.toMillis(expireTime);
        cache.put(key, new CacheEntry<>(value, expireTimeMillis));
    }

    // 获取缓存项的值,如果缓存项已过期,则返回null
    public V get(K key) {
        CacheEntry<K, V> entry = cache.get(key);
        if (entry != null && !entry.isExpired()) {
            return entry.value;
        } else {
            // 缓存项已过期或不存在,从缓存中移除(可选)
            cache.remove(key);
            return null;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SimpleCache<String, String> cache = new SimpleCache<>();

        // 添加缓存项,设置过期时间为5秒
        cache.put("key1", "value1", 5, TimeUnit.SECONDS);

        // 访问缓存项
        System.out.println("key1: " + cache.get("key1")); // 输出: value1

        // 等待6秒,使缓存项过期
        Thread.sleep(6000);

        // 再次访问缓存项,此时应返回null
        System.out.println("key1 after expiration: " + cache.get("key1")); // 输出: null
    }
}

案例三:任务分配系统

在这个案例中,我们使用 ConcurrentHashMap 来实现一个简单的任务分配系统,用于将任务分配给多个工作线程。

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TaskDistributor {
    // 使用ConcurrentHashMap存储任务和对应的处理线程
    private ConcurrentHashMap<String, String> taskAssignments = new ConcurrentHashMap<>();

    // 添加任务并分配处理线程
    public void assignTask(String taskId, String workerId) {
        taskAssignments.put(taskId, workerId);
    }

    // 获取任务的处理线程
    public String getWorkerForTask(String taskId) {
        return taskAssignments.get(taskId);
    }

    public static void main(String[] args) {
        TaskDistributor distributor = new TaskDistributor();

        // 创建工作线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // 模拟添加任务并分配处理线程
        for (int i = 0; i < 10; i++) {
            String taskId = "Task" + i;
            String workerId = "Worker" + (i % 3); // 简单地使用取模运算分配工作线程
            distributor.assignTask(taskId, workerId);
        }

        // 工作线程执行任务
        Runnable taskExecution = () -> {
            for (String taskId : distributor.taskAssignments.keySet()) {
                String workerId = distributor.getWorkerForTask(taskId);
                if (workerId.equals(Thread.currentThread().getName().substring(7))) {
                    System.out.println(Thread.currentThread().getName() + " is processing " + taskId);
                }
            }
        };

        // 启动工作线程
        for (int i = 0; i < 3; i++) {
            executorService.execute(new Thread(taskExecution, "Worker" + i));
        }

        // 关闭线程池(等待所有任务完成)
        executorService.shutdown();
    }
}

注意:在第三个案例中,由于线程池和任务分配是并发进行的,因此实际的任务分配和处理可能会有所不同。这里的示例主要是为了展示如何使用 ConcurrentHashMap 来存储和访问任务分配信息。在实际应用中,可能需要更复杂的逻辑来处理任务分配和线程同步。
这些案例展示了 ConcurrentHashMap 在不同场景下的应用,包括用户访问计数器、缓存系统和任务分配系统。通过使用 ConcurrentHashMap,我们可以实现线程安全的键值对存储和访问,从而满足高并发场景下的需求。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

golang操作sqlite3加速本地结构化数据查询

目录 摘要Sqlite3SQLite 命令SQLite 语法SQLite 数据类型列亲和类型——优先选择机制 SQLite 创建数据库SQLite 附加数据库SQLite 分离数据库 SQLite 创建表SQLite 删除表 SQLite Insert 语句SQLite Select 语句SQLite 运算符SQLite 算术运算符SQLite 比较运算符SQLite 逻辑运算…

Android v4和v7冲突

android.useAndroidXtrue android.enableJetifiertruev4转成AndroidX

【MySQL】优雅的使用MySQL实现分布式锁

MySQL实现分布式锁 引言二、基于唯一索引2.1、实现思路2.2、代码实现2.3、 测试代码2.4、小结 三、基于悲观锁3.1 、实现思路3.2、代码实现3.3、测试代码3.4、小结 四、基于乐观锁4.1 、实现思路4.2 、代码实现4.3 、测试代码4.4、小结 总结 引言 在文章《Redis实现分布式锁详…

生活小妙招之UE CaptureRT改

需求&#xff0c;四个不同的相机拍摄结果同屏分屏显示 一般的想法是四个Capture拍四张RT&#xff0c;然后最后在面片/UI上组合。这样的开销是创建4张RT&#xff0c;材质中采样4次RT。 以更省的角度&#xff0c;想要对以上流程做优化&#xff0c;4个相机拍摄是必须的&#xff…

1 JVM JDK JRE之间的区别以及使用字节码的好处

JDK jdk是编译java源文件成class文件的&#xff0c;我们使用javac命令把java源文件编译成class文件。 我们在java安装的目录下找到bin文件夹&#xff0c;如下图所示: 遵循着编译原理&#xff0c;把java源文件编译成JVM可识别的机器码。 其中还包括jar打包工具等。主要是针对…

【Unity功能集】TextureShop纹理工坊(二)图层(上)

项目源码&#xff1a;后期发布 索引 图层TextureLayer可见性激活性可编辑性绘画区域、绘画板绘画区域锚点导入图像 图层 在PS中&#xff0c;图层的概念贯穿始终&#xff08;了解PS图层&#xff09;&#xff0c;他可以称作PS最基础也是最强大的特性之一。 那么&#xff0c;在T…

贪心算法 part01

class Solution { public:int maxSubArray(vector<int>& nums) {int result INT32_MIN;int count 0;for (int i 0; i < nums.size(); i) {count nums[i];if (count > result) { // 取区间累计的最大值&#xff08;相当于不断确定最大子序终止位置&#xff…

二、FIFO缓存

FIFO缓存 1.FIFO缓存介绍2.FIFO缓存实现3.FIFO缓存总结 1.FIFO缓存介绍 FIFO&#xff08;First-In-First-Out&#xff09;缓存 是一种简单的缓存淘汰策略&#xff0c;它基于先进先出的原则来管理数据。当缓存达到容量限制并需要淘汰元素时&#xff0c;最先进入缓存的元素会被移…

王佩丰24节Excel学习笔记——第十四讲:日期函数

【以 Excel2010 系列学习&#xff0c;用 Office LTSC 专业增强版 2021 实践】 【本章小技巧】 掌握date()日期函数&#xff0c;配合年月日时分秒使用使用datedif()函数计算两个日期之前的差&#xff0c;重点记住参数三&#xff0c;差的值以哪种类型显示。使用weeknum/weekday,…

python--在服务器上面创建conda环境

今天刚开始使用服务器的时候使用上面的公共环境发现老师缺少模块&#xff0c; [guoyupingcins195 ~]$ conda --version Traceback (most recent call last): File "/home/miniconda3/bin/conda", line 12, in <module> from conda.cli import main Fil…

Trimble天宝三维激光扫描仪在建筑工程竣工测量中的应用【沪敖3D】

竣工测量是建筑项目竣工阶段的一个至关重要的环节&#xff0c;它为建筑工程的质量验收和成果核查提供了核心的参考依据。传统的竣工测量方法&#xff0c;如全站仪测量&#xff0c;主要依赖于现场人工操作&#xff0c;存在一些明显的局限性&#xff0c;例如作业时间长、工作量大…

SEO初学者-搜索引擎如何工作

搜索引擎基础搜索引擎是如何建立索引的搜索引擎如何对网页进行排名搜索引擎是如何个性化搜索结果的 搜索引擎的工作方式是使用网络爬虫抓取数十亿个页面。爬虫也称为蜘蛛或机器人&#xff0c;它们在网络上导航并跟踪链接以查找新页面。然后&#xff0c;这些页面会被添加到搜索引…

react中实现导出excel文件

react中实现导出excel文件 一、安装依赖二、实现导出功能三、自定义列标题四、设置列宽度五、样式优化1、安装扩展库2、设置样式3、扩展样式功能 在 React 项目中实现点击按钮后导出数据为 Excel 文件&#xff0c;可以使用 xlsx 和 file-saver 这两个库。 一、安装依赖 在项目…

Latex中表格添加底部文本注释并调整对齐

如何实现从第一个表到第三个表的转换&#xff0c; 其中主要涉及到两点&#xff1a; &#xff08;1&#xff09;底部脚注与表格自动对齐并缩进换行 &#xff08;2&#xff09;表格自适应页面宽度 底部脚注的对齐与换行缩进需要用到 \usepackage{threeparttable} \usepackage{…

MySQL基础 -----MySQL数据类型

目录 INT类型 tinyint类型 类型大小范围 测试tinyint类型数据 float类型 测试&#xff1a; 测试正常数据范围的数据 测试插入范围超过临界值的数据&#xff1a; 测试float类型的四舍五入 ​编辑 decimal类型 同样测试&#xff1a; 字符串类型 char类型 测试&…

【HarmonyOS NEXT】Web 组件的基础用法以及 H5 侧与原生侧的双向数据通讯

关键词&#xff1a;鸿蒙、ArkTs、Web组件、通讯、数据 官方文档Web组件用法介绍&#xff1a;文档中心 Web 组件加载沙箱中页面可参考我的另一篇文章&#xff1a;【HarmonyOS NEXT】 如何将rawfile中文件复制到沙箱中_鸿蒙rawfile 复制到沙箱-CSDN博客 目录 如何在鸿蒙应用中加…

ONES 功能上新|ONES Copilot、ONES Wiki 新功能一览

ONES Copilot 可基于工作项的标题、描述、属性信息&#xff0c;对工作项产生的动态和评论生成总结。 针对不同类型的工作项&#xff0c;总结输出的内容有对应的侧重点。 应用场景&#xff1a; 在一些流程步骤复杂、上下游参与成员角色丰富的场景中&#xff0c;工作项动态往往会…

使用qemu搭建armv7嵌入式开发环境

目录 目录 1 概述 2 环境准备 2.1 vexpress系列开发板介绍 2.2 安装工具 2.2.1 安装交叉工具链 2.2.2 安装qemu 2.2.3 安装其他工具 3 启动uboot 3.1 uboot下载与编译 3.1.1 下载 3.1.2 编译 3.2 使用qemu启动uboot 4 启动kernel 4.1 下载和编译kernel 4.1.1 下…

28.操作数据库

第三方库pymysql 使用安装命令 pip install pymysql 连接数据库、选择库、获取游标&#xff0c;执行创建表语句 from pymysql import Connection# 获取到mysql数据库连接对象 conn Connection(host"localhost", passwd"123456", user"root", …