读书笔记-Java并发编程的艺术--持续更新中

在这里插入图片描述

文章目录

  • 第1章 并发编程的挑战
    • 1.1 上下文切换
      • 1.1.1 多线程一定快吗
      • 1.1.2 如何减少上下文切换
    • 1.2 死锁
    • 1.3 资源限制的挑战
  • 第2章 Java并发机制的底层实现原理
  • 第3章 Java内存模型
  • 第4章 Java编发编程基础
  • 第5章 Java中的锁
  • 第6章 Java并发容器和框架
  • 第7章 Java中的13个原子操作类
  • 第8章 Java中的并发工具类
  • 第9章 Java中的线程池
  • 第10章 Executor框架
  • 第11章 Java并发编程实践

第1章 并发编程的挑战

1.1 上下文切换

即时是单核处理器也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现这个机制。时间片是CPU分配给多个线程的时间,因为时间片非常短,所以CPU通过不停地切换线程执行让我们感觉多个线程是同时执行的,时间片一般是几十毫秒。

CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。

1.1.1 多线程一定快吗

下面的代码演示串行和并发执行并累加操作的时间,并发执行一定比串行执行快吗?

public class ConcurrencyTest {private static final int count = 200000000;public static void main(String[] args) throws InterruptedException {concurrency(count);serial(count);}private static void concurrency(int count) throws InterruptedException {long start = System.currentTimeMillis();Thread thread = new Thread(new Runnable() {@Overridepublic void run() {int a = 0;for (int i = 0; i < count; i++) {a +=5;}}});thread.start();int b = 0;for (int i = 0; i < count; i++) {b--;}thread.join();long time = System.currentTimeMillis() - start;System.out.println("count:" + formatToTenThousand(count) +", concurrency: " + time + "ms,b=" + b);}private static void serial(int count) {long start = System.currentTimeMillis();int a = 0;for (int i = 0; i < count; i++) {a +=5;}int b = 0;for (int i = 0; i < count; i++) {b--;}long time = System.currentTimeMillis() - start;System.out.println("count:" + formatToTenThousand(count) +", serial:" + time+"ms, b="+b+", a="+a);System.out.println();}private static String formatToTenThousand(int number) {double tenThousand = (double) number / 10000;DecimalFormat df = new DecimalFormat("0万");return df.format(tenThousand);}}

打印:

count:20000万, concurrency: 15ms,b=-200000000
count:20000万, serial:10ms, b=-200000000, a=1000000000

上述问题的答案是不一定,结果跟机器的核数相关,如果是1核处理器,那么肯定串行快,因为省略了创建线程和多线程上下文切换的时间,如果是多核,那么一般还是并发执行更快。而且这个代码示例中并发也只是两个线程,执行的结果意义不大。
我执行了多次也没有出现书中所描述的随着count数据量增大而出现并发执行更快的趋势,反而是串行一直都更快,即使count大小为两亿。而且这个代码示例基本没有io的处理,代表意义太有限。以我的经验来看,只是涉及在cpu中的计算,而没有与数据库等资源的交互,那么使用多线程意义不大。

1.1.2 如何减少上下文切换

减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程。

  • 无锁并发编程。多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁、如将数据的ID取余分段,不同的线程处理不同段的数据。
  • CAS算法。Java的java.util.concurrent.atomic包使用CAS算法来更新数据,而不需要加锁。
  • 使用最少线程。避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态。
  • 协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。

java.util.concurrent.atomic包:
在这里插入图片描述

对于Java开发工程师而言,尽量使用JDK并发包提供的并发容器和工具类来解决并发问题,因为这些类都已经通过了充分的测试和优化

1.2 死锁

下面这段代码只是演示死锁的场景,在现实中你可能不会写出这样的代码。但是,在一些更为复杂的场景中,你可能会遇到这样的问题,比如t1拿到锁之后,因为一些异常情况没有释放锁(死循环)。又或者是t1拿到一个数据库锁,释放锁的时候抛出了异常,没释放掉。

public class DeadLockDemo {private static String A = "A";private static String B = "B";public static void main(String[] args) {new DeadLockDemo().deadLock();}private void deadLock() {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (A) {try {Thread.currentThread().sleep(2000L);} catch (InterruptedException e) {e.printStackTrace();}synchronized (B) {System.out.println("1");}}}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (B) {try {Thread.currentThread().sleep(2000L);} catch (InterruptedException e) {e.printStackTrace();}synchronized (A) {System.out.println("2");}}}});t1.start();t2.start();}
}

避免死锁的几个常见方法:

  • 避免一个线程同时获取多个锁。
  • 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
  • 尝试使用定时锁,使用lock.tryLock(timeout) 来替代使用内部锁机制。
  • 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

1.3 资源限制的挑战

(1)什么是资源限制
资源限制就是程序的执行速度受限于计算机硬件或软件资源。
例如,服务器的带宽只有2Mb/s,每个资源的下载速度是1Mb/s,系统启动10个线程下载资源,下载速度不会变成10Mb/s,所以在进行并发编程时,要考虑这些资源的限制。硬件资源限制有带宽的上传/下载速度、硬盘读写速度和CPU的处理速度。软件资源限制有数据库的连接数和socket连接数等。

(2)资源限制引发的问题
在并发编程中,将代码执行速度加快的原则是将代码中串行执行的部分变成并发执行,但是如果将某段串行的代码并发执行,因为受限于资源,仍然在串行执行,这时候程序不仅不会加快速度,反而会更慢,因为增加了上下文切换和资源调度的时间。例如,之前看到一段程序使用多线程在办公网并发地下载和处理数据时,导致CPU利用率达到100%,几个小时都不能运行完成任务,后来修改为单线程,一个小时就执行完成了。

(3)如何解决资源限制的问题
对于硬件资源限制,可以考虑使用集群并行执行程序。既然单机的资源有限制,那么就让程序在多机上运行。比如使用ODPS、Hadoop或者自己搭建服务器集群,不同的机器处理不同的数据。可以通过“数据ID%机器数”,计算得到一个机器编号,然后由对应编号的机器处理这笔数据。
对于软件资源限制,可以考虑使用资源池将资源复用。比如使用连接池将数据库和socket连接复用,或者在调用对方webservice接口获取数据时,只建立一个连接。

WebService 与 Socket 区别

(4)在资源限制情况下进行并发编程
如何在资源限制的情况下,让程序执行得更快呢?方法就是,根据不同的资源限制调整程序的并发度,比如下载文件程序依赖于两个资源—带宽和硬盘读写速度。有数据库操作时,涉及数据库连接数,如果SQL语句执行非常快,而线程的数量比数据库连接数大很多,则某些线程会被阻塞,等待数据库连接。

第2章 Java并发机制的底层实现原理

第3章 Java内存模型

第4章 Java编发编程基础

第5章 Java中的锁

第6章 Java并发容器和框架

第7章 Java中的13个原子操作类

第8章 Java中的并发工具类

第9章 Java中的线程池

第10章 Executor框架

第11章 Java并发编程实践

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

不知道是该怎么引用多个函数片段?具体示例如代码

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

Linux之共享内存mmap用法实例(六十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

三前奏:获取/ 读取/ 评估数据【数据分析】

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 前面的博客 数据分析—技术栈和开发环境搭建 …

【全网最全】2024电工杯数学建模B题问题一14页论文+19建模过程代码+py代码+2种保奖思路+数据等(后续会更新成品论文等)

您的点赞收藏是我继续更新的最大动力&#xff01; 一定要点击如下的卡片链接&#xff0c;那是获取资料的入口&#xff01; 【全网最全】2024电工杯数学建模B题问一论文19建模过程代码py代码2种保奖思路数据等&#xff08;后续会更新成品论文等&#xff09;「首先来看看目前已…

香蕉成熟度检测YOLOV8NANO

香蕉成熟度检测YOLOV8NANO&#xff0c;采用YOLOV8NANO训练&#xff0c;得到PT模型&#xff0c;然后转换成ONNX模型&#xff0c;让OEPNCV调用&#xff0c;从而摆脱PYTORCH依赖&#xff0c;支持C。python&#xff0c;安卓开发。能检测六种香蕉类型freshripe freshunripe overripe…

轻松拿捏C语言——【字符串函数】的使用及模拟实现

&#x1f970;欢迎关注 轻松拿捏C语言系列&#xff0c;来和 小哇 一起进步&#xff01;✊ &#x1f389;创作不易&#xff0c;请多多支持&#x1f389; &#x1f308;感谢大家的阅读、点赞、收藏和关注&#x1f495; &#x1f339;如有问题&#xff0c;欢迎指正 感谢 目录 一、…

力扣--哈希表13.罗马数字转整数

首先我们可以知道&#xff0c;一个整数&#xff0c;最多由2个罗马数字组成。 思路分析 这个方法能够正确将罗马数字转换为阿拉伯数字的原因在于它遵循了罗马数字的规则&#xff0c;并且对这些规则进行了正确的编码和处理。 罗马数字规则 罗马数字由以下字符组成&#xff1a…

解决 Failed to parse remote port from server output【Remote-SSH】【VSCode】

描述 一早起来&#xff0c;发现remote-ssh无法进入服务器容器&#xff0c;本地使用git bash进行ssh可正常连接服务器&#xff0c;基本确定是vscode工具本身的问题。重装本地用户的.vscode相关目录清空&#xff0c;vscode重装均无果&#xff0c;不建议尝试。弹窗信息为Could no…

element-plusDate Picker 日期选择器获取年月日

代码逻辑 对选择日期选择后进行搜索 &#xff1a; function dataValue(value) {console.log(value);scenic_list.value arrlist.value.filter(function (item) {// 判断是否满足搜索条件if (String(item.create_time).indexOf(String(value)) > -1) {return scenic_list}}…

WordPress国外超人气主题Vikinger汉化版

WordPress国外超人气主题Vikinger汉化版 前言效果图安装教程领取主题下期更新预报 前言 我们在上一个教程已经学过如何安装WordPress&#xff0c;所以现在不用多说。 效果图 安装教程 下载后先本地解压&#xff0c;找到vikinger.zip文件&#xff0c;上传安装并启用主题。 访…

【Linux】进程终止与进程等待

目录 进程终止 errno exit和_exit 进程等待 wait和waitpid 宏&#xff1a;WIFEXITED 非阻塞等待 进程终止 下面要谈的一个话题就是进程终止&#xff0c;就是说一个进程退出了&#xff0c;可能有三种情况 1.进程代码执行完&#xff0c;结果是正确的 2.进程代码执行完&…

c++入门的基础知识

c入门 C是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库&#xff0c;以及编程范式等。熟悉C语言之后&#xff0c;对C学习有一定的帮助&#xff0c;本章节主要目标&#xff1a; 补充C语言语法的不足&#xff0c;以及C是如何对C语言设计…

手机边听边充音频转接器双盲插系列:便捷充电,畅享音乐6500

在快节奏的生活中&#xff0c;手机已经成为我们不可或缺的日常用品。无论是工作、学习还是娱乐&#xff0c;手机都扮演着重要角色。然而&#xff0c;当我们沉浸在音乐的海洋中时&#xff0c;手机电量不足的困扰却时常打断我们的美好体验。为了解决这一难题&#xff0c;手机边听…

WEB攻防【2】——ASPX/.NET项目/DLL反编译/未授权访问/配置调试报错

ASP&#xff1a;windowsiisaspaccess .net&#xff1a;windowsiisaspxsqlserver IIS上的安全问题也会影响到 WEB漏洞&#xff1a;本身源码上的问题 服务漏洞&#xff1a;1、中间件 2、数据库 3、第三方软件 #知识点: 1、.NET:配置调试-信息泄绵 2、.NET:源码反编译-DLL…

5.23.12 计算机视觉的 Inception 架构

1. 介绍 分类性能的提升往往会转化为各种应用领域中显着的质量提升&#xff0c;深度卷积架构的架构改进可用于提高大多数其他计算机视觉任务的性能&#xff0c;这些任务越来越依赖于高质量的学习视觉特征。在 AlexNet 功能无法与手工设计、制作的解决方案竞争的情况下&#xf…

python 面对对象 类 魔法方法

魔法方法 一、__init__ 构造函数&#xff0c;可以理解为初始化 触发条件&#xff1a;在实例化的时候就会触发 class People():def __init__(self, name):print(init被执行)self.name namedef eat(self):print(f{self.name}要吃饭)a People(张三) a.eat() # in…

K8S认证|CKA题库+答案| 12. 查看Pod日志

12、查看Pod日志 您必须在以下Cluster/Node上完成此考题&#xff1a; Cluster Master node Worker node k8s master …

以太坊钱包

以太坊钱包是你通往以太坊系统的门户。它拥有你的密钥&#xff0c;并且可以代表你创建和广播交易。选择一个以太坊钱包可能很困难&#xff0c;因为有很多不同功能和设计选择。有些更适合初学者&#xff0c;有些更适合专家。即使你现在选择一个你喜欢的&#xff0c;你可能会决定…

深度学习Day-18:ResNet50V2算法实战与解析

&#x1f368; 本文为&#xff1a;[&#x1f517;365天深度学习训练营] 中的学习记录博客 &#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制] 要求&#xff1a; 根据本文Tensorflow代码&#xff0c;编写对应的Pytorch代码了解ResNetV2与ResNetV的区别 一、 基础…

小红书云原生 Kafka 技术剖析:分层存储与弹性伸缩

面对 Kafka 规模快速增长带来的成本、效率和稳定性挑战时&#xff0c;小红书大数据存储团队采取云原生架构实践&#xff1a;通过引入冷热数据分层存储、容器化技术以及自研的负载均衡服务「Balance Control」&#xff0c;成功实现了集群存储成本的显著降低、分钟级的集群弹性迁…