读书笔记-Java并发编程的艺术-第1章 并发编程的挑战

news2025/3/17 7:37:45

在这里插入图片描述

文章目录

  • 1.1 上下文切换
    • 1.1.1 多线程一定快吗
    • 1.1.2 如何减少上下文切换
  • 1.2 死锁
  • 1.3 资源限制的挑战

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() {
            @Override
            public 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() {
            @Override
            public 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() {
            @Override
            public 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语句执行非常快,而线程的数量比数据库连接数大很多,则某些线程会被阻塞,等待数据库连接。


读书笔记-Java并发编程的艺术

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

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

相关文章

H3CNE-6-ICMP数据包分析

ICMP&#xff1a;Internet Control Message Protocol ICMP用来传递差错、控制、查询等信息 Wireshark抓包 Wireshark下载国内镜像 ICMP数据包格式 Type&#xff1a;表示ICMP消息类型 Code&#xff1a;表示同一消息类型中的不同信息 ICMP消息类型和编码类型 ICMP应用 &…

idea中显示git的Local Changes

1. 第一打开idea中的Settings文件 2. 找到Version Contro中的commint 3. 取消勾选应用即可 4. 本地提交就会显示出来

Python高级进阶--dict字典

dict字典⭐⭐ 1. 字典简介 dictionary&#xff08;字典&#xff09; 是 除列表以外 Python 之中 最灵活 的数据类型&#xff0c;类型为dict 字典同样可以用来存储多个数据字典使用键值对存储数据 2. 字典的定义 字典用{}定义键值对之间使用,分隔键和值之间使用:分隔 d {中…

【Linux网络编程】传输层中的TCP和UDP(TCP篇)

【Linux网络编程】传输层中的TCP和UDP&#xff08;TCP篇&#xff09; 目录 【Linux网络编程】传输层中的TCP和UDP&#xff08;TCP篇&#xff09;TCP协议TCP协议段格式确认应答&#xff08;ACK&#xff09;机制&#xff08;保证可靠性&#xff09;超时重传机制连接管理机制理解T…

“等保测评与安全运维的协同:保障企业网络安宁

"等保测评与安全运维的协同&#xff1a;保障企业网络安宁"是一个涉及信息安全领域的重要话题。这里&#xff0c;我们可以从几个方面来探讨这个主题。 1. 等保测评&#xff08;等级保护测评&#xff09; 等保测评&#xff0c;即信息安全等级保护测评&#xff0c;是依…

社交媒体数据恢复:连信

在使用连信的过程中&#xff0c;如果我们误删了重要的照片或者文件&#xff0c;可以通过以下步骤进行数据恢复&#xff1a; 一、有备份恢复 若你在删除之前已经备份了相关照片或文件&#xff0c;那么恢复起来就相对容易一些。以下是具体的恢复步骤&#xff1a; 登录连信账号&…

vue data中的return

vue 的data return 是干啥的呢&#xff0c;vue中页面中绑定的变量都要放在data的return中&#xff0c;可以赋值&#xff0c;值可在script中改&#xff0c;修改引用就用this了 如果不使用return包裹的数据会在项目的全局中可见&#xff0c;会造成变量污染&#xff1b; 使用retu…

虚拟机启动Operating System not found找不到操作系统

错误信息 PEX-E51 No SHCP or proxyDHCP offers were received. PXE-M0F: Exiting Intel PXE ROM. Operating System not found解决方法1 到服务里面检查跟vmware相关的服务是否已经全部启动 如果服务怎么都无法启动&#xff0c;最简单的办法还是重装vmware 解决方法2 &#…

音视频开发5 补充 - Nginx搭建rtmp流媒体服务器,目的是让ffmpeg 可以直播推流

直播推流 ffmpeg -re -i out.mp4 -c copy flv rtmp://server/live/streamName -re, 表示按时间戳读取文件 参考&#xff1a; Nginx 搭建 rtmp 流媒体服务器 (Ubuntu 16.04) https://www.jianshu.com/p/16741e363a77 第一步 准备工作 安装nginx需要的依赖包 打开 ubutun 终端…

2024年5月26日 十二生肖 今日运势

小运播报&#xff1a;2024年5月26日&#xff0c;星期日&#xff0c;农历四月十九 &#xff08;甲辰年己巳月庚寅日&#xff09;&#xff0c;法定节假日。 红榜生肖&#xff1a;马、猪、狗 需要注意&#xff1a;牛、蛇、猴 喜神方位&#xff1a;西北方 财神方位&#xff1a;…

【2024最新华为OD-C卷试题汇总】传递悄悄话的最长时间(100分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; 文章目录 前…

3.Redis之Redis的环境搭建redis客户端介绍

1.版本的选取 安装 Redis&#xff1a;Redis 5 系列~~ 在 Linux 中进行安装~~ Redis 官方是不支持 Windows 版本的~~ 微软维护了一个 Windows 版本的 Redis 分支 Centos和Ubuntu.Docker 2.如何进行安装&#xff1f;&#xff1f;&#xff1f; 1.ubuntu 2.centos yum instal…

欧拉函数、快速幂、扩展欧几里得算法、中国剩余定理和高斯消元

欧拉函数 给定 n 个正整数 ai&#xff0c;请你求出每个数的欧拉函数。 欧拉函数的定义1∼N 中与 N 互质的数的个数被称为欧拉函数&#xff0c;记为 ϕ(N)。 若在算数基本定理中&#xff0c;Np1a11p2a2…pmm&#xff0c;则&#xff1a;ϕ(N) Np1−1/p1p2−1/p2…pm−1/pm 输…

最热门好用骨传导耳机推荐!!分享六大实用选购技巧助你挑选!

耳机基本是每人人手一台&#xff0c;不管是在地铁上还是在公交上&#xff0c;都可以看到很多人戴着耳机度过空余的时光&#xff0c;甚至现在人们在耳机的选择方面更加偏向于骨传导耳机&#xff0c;开放耳道的奇特设计在户外佩戴的时候可以更好的感知到周围的环境音&#xff0c;…

视频汇聚平台LntonCVS视频监控系统前端错误日志记录及Debug模式详细讲解

LntonCVS作为一种支持GB28181标准的流媒体服务平台&#xff0c;旨在提供一个能够整合不同厂商设备、便于管理和扩展的解决方案&#xff0c;以适应日益复杂的视频监控环境。通过实现设备的统一管理和流媒体的高效传输&#xff0c;LntonCVS帮助构建更加灵活和强大的视频监控系统。…

记录docker ps查找指定容器的几个命令

1.docker ps | grep registry 查询包含registry的容器 2.docker ps | grep -E "reigistry\s" 开启正则匹配模式&#xff0c;匹配registry后面为空格的容器&#xff0c;若是匹配一整行可以这样写docker ps | grep -E "^([0-9a-f]{12})\sregistry\s.*" 这…

中药垂直大模型汇总

中药垂直大模型汇总 2023 ShenNong-TCM Paper: ShenNong-TCM: A Traditional Chinese Medicine Large Language Model Data: https://huggingface.co/datasets/michaelwzhu/ShenNong_TCM_Dataset Code:https://github.com/michael-wzhu/ShenNong-TCM-LLM ShenNong-TCM由华东…

开关电源AC-DC(15W 3-18V可调)

简介: 该模块使用PI的TNY268PN电源芯片制作的开关电源,实现最大功率15W 3-18V可调输出(更改反馈电阻)隔离式反激电源; 简介:该模块使用PI的TNY268PN电源芯片制作的开关电源,实现最大功率15W 3-18V可调输出(更改反馈电阻,现电路图输出5V)隔离式反激电源; 一、产品简…

全域运营是本地生活服务的新模式吗?

最近&#xff0c;本地生活赛道又出现了一个新的说法&#xff0c;即全域运营是本地生活的下半场。事实上&#xff0c;这一论断并非空穴来风&#xff0c;而是有真凭实据。 作为多家互联网大厂重点布局的业务板块&#xff0c;本地生活的火爆程度早已有目共睹。根据多家互联网大厂…

国赛练习(1)

Unzip 软连接 软连接是linux中一个常用命令&#xff0c;它的功能是为某一个文件在另外一个位置建立一个同步的链接。换句话说&#xff0c;也可以理解成Windows中的快捷方式 注意&#xff1a;在创建软连接的文件的所有目录下不能有重名的文件 打开环境&#xff0c;是文件上传&am…