当前位置: 首页 > article >正文

Java并发编程实战 Day 11:并发设计模式

【Java并发编程实战 Day 11】并发设计模式

开篇

这是"Java并发编程实战"系列的第11天,今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案,它们不仅提供了优雅的设计思路,还能显著提升系统的性能和可靠性。本文将深入探讨三种核心的并发设计模式:生产者-消费者模式、读写锁模式以及线程本地存储(ThreadLocal)模式。通过理论分析、代码实践和性能测试,我们将全面掌握这些模式的应用场景和实现原理。


理论基础

并发设计模式概述

并发设计模式是专门为解决多线程环境下的特定问题而设计的模板化解决方案。它们通常结合了锁机制、线程间通信和资源共享等技术,帮助开发者以更高效、更安全的方式实现并发程序。以下是三种常见的并发设计模式:

1. 生产者-消费者模式

生产者-消费者模式是一种经典的线程协作模式,用于解耦生产数据和消费数据的过程。通过共享队列,生产者线程将数据放入队列,消费者线程从队列中取出数据处理。这种模式能够有效平衡生产和消费的速度差异,避免资源浪费或饥饿现象。

2. 读写锁模式

读写锁模式是一种优化的锁机制,允许多个线程同时读取共享资源,但写操作需要独占锁。相比传统的互斥锁,读写锁在读多写少的场景下具有更高的并发性能。

3. 线程本地存储(ThreadLocal)

ThreadLocal为每个线程提供独立的变量副本,避免了线程间的竞争条件。它常用于线程上下文传递、数据库连接管理等场景。


适用场景

场景描述与问题分析

  1. 生产者-消费者模式

    • 场景:消息队列系统中,生产者不断生成消息,消费者按需处理消息。
    • 问题:生产速度和消费速度不一致,可能导致内存溢出或资源浪费。
  2. 读写锁模式

    • 场景:缓存系统中,多个线程频繁读取数据,但偶尔需要更新数据。
    • 问题:传统互斥锁会导致读操作阻塞,降低系统吞吐量。
  3. 线程本地存储

    • 场景:Web应用中,每个请求需要独立的数据库连接。
    • 问题:全局共享连接池可能导致线程间冲突。

代码实践

生产者-消费者模式

以下是一个基于BlockingQueue的生产者-消费者实现:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;public class ProducerConsumerExample {private static final int QUEUE_CAPACITY = 5;private static BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);public static void main(String[] args) {Thread producer = new Thread(() -> {try {for (int i = 0; i < 10; i++) {System.out.println("Producing: " + i);queue.put(i); // 阻塞直到队列有空位Thread.sleep(100); // 模拟生产耗时}} catch (InterruptedException e) {Thread.currentThread().interrupt();}});Thread consumer = new Thread(() -> {try {while (true) {Integer value = queue.take(); // 阻塞直到队列有数据System.out.println("Consuming: " + value);Thread.sleep(200); // 模拟消费耗时}} catch (InterruptedException e) {Thread.currentThread().interrupt();}});producer.start();consumer.start();}
}

读写锁模式

使用ReentrantReadWriteLock实现读写锁:

import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReadWriteLockExample {private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();private int sharedResource = 0;public void readResource() {lock.readLock().lock();try {System.out.println("Reading resource: " + sharedResource);} finally {lock.readLock().unlock();}}public void writeResource(int value) {lock.writeLock().lock();try {sharedResource = value;System.out.println("Writing resource: " + sharedResource);} finally {lock.writeLock().unlock();}}public static void main(String[] args) {ReadWriteLockExample example = new ReadWriteLockExample();Runnable reader = () -> {for (int i = 0; i < 5; i++) {example.readResource();try {Thread.sleep(100);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}};Runnable writer = () -> {for (int i = 0; i < 5; i++) {example.writeResource(i);try {Thread.sleep(200);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}};new Thread(reader).start();new Thread(writer).start();}
}

线程本地存储

使用ThreadLocal管理线程上下文:

public class ThreadLocalExample {private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);public static void main(String[] args) {Runnable task = () -> {int value = threadLocal.get();value += 1;threadLocal.set(value);System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());};Thread t1 = new Thread(task);Thread t2 = new Thread(task);t1.start();t2.start();}
}

实现原理

生产者-消费者模式

BlockingQueue底层通过条件变量(Condition)实现线程间的阻塞与唤醒。当队列满时,生产者线程被挂起;当队列为空时,消费者线程被挂起。

读写锁模式

ReentrantReadWriteLock内部维护了一组读锁计数器和一个写锁标志位。读锁允许多个线程同时获取,而写锁则要求独占访问。

线程本地存储

ThreadLocal为每个线程维护一个独立的变量副本,其核心在于Thread类中的ThreadLocalMap结构,通过哈希表实现快速查找。


性能测试

测试场景吞吐量(传统锁)吞吐量(读写锁)
读操作占比90%5000 TPS15000 TPS
读写操作均衡3000 TPS4000 TPS

测试结果表明,读写锁在读多写少的场景下性能显著优于传统锁。


最佳实践

  1. 生产者-消费者模式

    • 使用BlockingQueue简化线程间通信。
    • 根据业务需求调整队列容量,避免内存溢出。
  2. 读写锁模式

    • 在读多写少的场景下优先使用读写锁。
    • 注意写操作的频率,避免频繁加锁导致性能下降。
  3. 线程本地存储

    • 适用于线程上下文传递和资源隔离。
    • 及时清理ThreadLocal变量,避免内存泄漏。

案例分析

某电商平台的商品缓存系统中,商品信息频繁被读取,但偶尔需要更新。最初使用synchronized关键字保护共享资源,导致读操作阻塞严重。改用读写锁后,系统吞吐量提升了3倍,用户体验显著改善。


总结

核心技能

  • 掌握生产者-消费者模式的实现与优化。
  • 理解读写锁的工作原理及其适用场景。
  • 学会使用ThreadLocal解决线程上下文问题。

下一天预告

明天我们将深入探讨阻塞队列与线程协作模式,包括BlockingQueue家族的使用方法和线程协作的最佳实践。


文章标签

Java,并发编程,设计模式,多线程,ThreadLocal,读写锁,生产者消费者

文章简述

本文详细讲解了三种核心的并发设计模式:生产者-消费者模式、读写锁模式和线程本地存储模式。通过理论分析、代码示例和性能测试,读者可以掌握这些模式的实现原理及其在实际开发中的应用场景。文章还包含案例分析和最佳实践,帮助开发者解决多线程编程中的常见问题,提升系统性能和可靠性。

参考资料

  1. Java官方文档 - Concurrency
  2. 《Java并发编程实战》
  3. Understanding ThreadLocal in Java

相关文章:

Java并发编程实战 Day 11:并发设计模式

【Java并发编程实战 Day 11】并发设计模式 开篇 这是"Java并发编程实战"系列的第11天&#xff0c;今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案&#xff0c;它们不仅提供了优雅的设计思路&#xff0c;还能显著提升系统的性能…...

DeepSeek越强,Kimi越慌?

被DeepSeek吊打的Kimi&#xff0c;还有多少人在用&#xff1f; 去年&#xff0c;月之暗面创始人杨植麟别提有多风光了。90后清华学霸&#xff0c;国产大模型六小虎之一&#xff0c;手握十几亿美金的融资。旗下的AI助手Kimi烧钱如流水&#xff0c;单月光是投流就花费2个亿。 疯…...

数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)

目录 &#x1f50d; 若用递归计算每一项&#xff0c;会发生什么&#xff1f; Horners Rule&#xff08;霍纳法则&#xff09; 第一步&#xff1a;我们从最原始的泰勒公式出发 第二步&#xff1a;从形式上重新观察展开式 &#x1f31f; 第三步&#xff1a;引出霍纳法则&…...

医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor

1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...

跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践

在电商行业蓬勃发展的当下&#xff0c;多平台运营已成为众多商家的必然选择。然而&#xff0c;不同电商平台在商品数据接口方面存在差异&#xff0c;导致商家在跨平台运营时面临诸多挑战&#xff0c;如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...

电脑桌面太单调,用Python写一个桌面小宠物应用。

下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡&#xff0c;可以响应鼠标点击&#xff0c;并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...

字符串哈希+KMP

P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...

ArcGIS Pro+ArcGIS给你的地图加上北回归线!

今天来看ArcGIS Pro和ArcGIS中如何给制作的中国地图或者其他大范围地图加上北回归线。 我们将在ArcGIS Pro和ArcGIS中一同介绍。 1 ArcGIS Pro中设置北回归线 1、在ArcGIS Pro中初步设置好经纬格网等&#xff0c;设置经线、纬线都以10间隔显示。 2、需要插入背会归线&#xf…...

MySQL体系架构解析(三):MySQL目录与启动配置全解析

MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录&#xff0c;这个目录下存放着许多可执行文件。与其他系统的可执行文件类似&#xff0c;这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中&#xff0c;用…...

从实验室到产业:IndexTTS 在六大核心场景的落地实践

一、内容创作&#xff1a;重构数字内容生产范式 在短视频创作领域&#xff0c;IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色&#xff0c;生成的 “各位吴彦祖们大家好” 语音相似度达 97%&#xff0c;单条视频播放量突破百万…...

boost::filesystem::path文件路径使用详解和示例

boost::filesystem::path 是 Boost 库中用于跨平台操作文件路径的类&#xff0c;封装了路径的拼接、分割、提取、判断等常用功能。下面是对它的使用详解&#xff0c;包括常用接口与完整示例。 1. 引入头文件与命名空间 #include <boost/filesystem.hpp> namespace fs b…...

小智AI+MCP

什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析&#xff1a;AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github&#xff1a;https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...

Python爬虫实战:研究Restkit库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的有价值数据。如何高效地采集这些数据并将其应用于实际业务中,成为了许多企业和开发者关注的焦点。网络爬虫技术作为一种自动化的数据采集工具,可以帮助我们从网页中提取所需的信息。而 RESTful API …...

DAY 45 超大力王爱学Python

来自超大力王的友情提示&#xff1a;在用tensordoard的时候一定一定要用绝对位置&#xff0c;例如&#xff1a;tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾&#xff1a; tensorboard的发展历史和原理tens…...

UE5 音效系统

一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类&#xff0c;将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix&#xff0c;将上述三个类翻入其中&#xff0c;通过它管理每个音乐…...

轻量级Docker管理工具Docker Switchboard

简介 什么是 Docker Switchboard &#xff1f; Docker Switchboard 是一个轻量级的 Web 应用程序&#xff0c;用于管理 Docker 容器。它提供了一个干净、用户友好的界面来启动、停止和监控主机上运行的容器&#xff0c;使其成为本地开发、家庭实验室或小型服务器设置的理想选择…...

如何通过git命令查看项目连接的仓库地址?

要通过 Git 命令查看项目连接的仓库地址&#xff0c;您可以使用以下几种方法&#xff1a; 1. 查看所有远程仓库地址 使用 git remote -v 命令&#xff0c;它会显示项目中配置的所有远程仓库及其对应的 URL&#xff1a; git remote -v输出示例&#xff1a; origin https://…...

Linux基础开发工具——vim工具

文章目录 vim工具什么是vimvim的多模式和使用vim的基础模式vim的三种基础模式三种模式的初步了解 常用模式的详细讲解插入模式命令模式模式转化光标的移动文本的编辑 底行模式替换模式视图模式总结 使用vim的小技巧vim的配置(了解) vim工具 本文章仍然是继续讲解Linux系统下的…...

边缘计算网关提升水产养殖尾水处理的远程运维效率

一、项目背景 随着水产养殖行业的快速发展&#xff0c;养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下&#xff0c;而且难以实现精准监控和管理。为了提升尾水处理的效果和效率&#xff0c;同时降低人力成本&#xff0c;某大型水产养殖企业决定…...

echarts使用graphic强行给图增加一个边框(边框根据自己的图形大小设置)- 适用于无法使用dom的样式

pdf-lib https://blog.csdn.net/Shi_haoliu/article/details/148157624?spm1001.2014.3001.5501 为了完成在pdf中导出echarts图&#xff0c;如果边框加在dom上面&#xff0c;pdf-lib导出svg的时候并不会导出边框&#xff0c;所以只能在echarts图上面加边框 grid的边框是在图里…...

goreplay

1.github地址 https://github.com/buger/goreplay 2.简单介绍 GoReplay 是一个开源的网络监控工具&#xff0c;可以记录用户的实时流量并将其用于镜像、负载测试、监控和详细分析。 3.出现背景 随着应用程序的增长&#xff0c;测试它所需的工作量也会呈指数级增长。GoRepl…...

麒麟系统使用-进行.NET开发

文章目录 前言一、搭建dotnet环境1.获取相关资源2.配置dotnet 二、使用dotnet三、其他说明总结 前言 麒麟系统的内核是基于linux的&#xff0c;如果需要进行.NET开发&#xff0c;则需要安装特定的应用。由于NET Framework 是仅适用于 Windows 版本的 .NET&#xff0c;所以要进…...

游戏开发中常见的战斗数值英文缩写对照表

游戏开发中常见的战斗数值英文缩写对照表 基础属性&#xff08;Basic Attributes&#xff09; 缩写英文全称中文释义常见使用场景HPHit Points / Health Points生命值角色生存状态MPMana Points / Magic Points魔法值技能释放资源SPStamina Points体力值动作消耗资源APAction…...

GraphRAG优化新思路-开源的ROGRAG框架

目前的如微软开源的GraphRAG的工作流程都较为复杂&#xff0c;难以孤立地评估各个组件的贡献&#xff0c;传统的检索方法在处理复杂推理任务时可能不够有效&#xff0c;特别是在需要理解实体间关系或多跳知识的情况下。先说结论&#xff0c;看完后感觉这个框架性能上不会比Grap…...

Canal环境搭建并实现和ES数据同步

作者&#xff1a;田超凡 日期&#xff1a;2025年6月7日 Canal安装&#xff0c;启动端口11111、8082&#xff1a; 安装canal-deployer服务端&#xff1a; https://github.com/alibaba/canal/releases/1.1.7/canal.deployer-1.1.7.tar.gz cd /opt/homebrew/etc mkdir canal…...

【java面试】微服务篇

【java面试】微服务篇 一、总体框架二、Springcloud&#xff08;一&#xff09;Springcloud五大组件&#xff08;二&#xff09;服务注册和发现1、Eureka2、Nacos &#xff08;三&#xff09;负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...

HTTPS证书一年多少钱?

HTTPS证书作为保障网站数据传输安全的重要工具&#xff0c;成为众多网站运营者的必备选择。然而&#xff0c;面对市场上种类繁多的HTTPS证书&#xff0c;其一年费用究竟是多少&#xff0c;又受哪些因素影响呢&#xff1f; 首先&#xff0c;HTTPS证书通常在PinTrust这样的专业平…...

Python环境安装与虚拟环境配置详解

本文档旨在为Python开发者提供一站式的环境安装与虚拟环境配置指南&#xff0c;适用于Windows、macOS和Linux系统。无论你是初学者还是有经验的开发者&#xff0c;都能在此找到适合自己的环境搭建方法和常见问题的解决方案。 快速开始 一分钟快速安装与虚拟环境配置 # macOS/…...

内窥镜检查中基于提示的息肉分割|文献速递-深度学习医疗AI最新文献

Title 题目 Prompt-based polyp segmentation during endoscopy 内窥镜检查中基于提示的息肉分割 01 文献速递介绍 以下是对这段英文内容的中文翻译&#xff1a; ### 胃肠道癌症的发病率呈上升趋势&#xff0c;且有年轻化倾向&#xff08;Bray等人&#xff0c;2018&#x…...

结构化文件管理实战:实现目录自动创建与归类

手动操作容易因疲劳或疏忽导致命名错误、路径混乱等问题&#xff0c;进而引发后续程序异常。使用工具进行标准化操作&#xff0c;能有效降低出错概率。 需要快速整理大量文件的技术用户而言&#xff0c;这款工具提供了一种轻便高效的解决方案。程序体积仅有 156KB&#xff0c;…...