并发执行一定比串行执行快吗?

news2024/9/24 1:20:03

一、多线程的两个主要方向

并发:多线程之间各自执行各自的互不影响
并行:多线程之间互相竞争资源,进行读写的时候可能会产生相互覆盖

二、上下文切换

1.什么是上下文切换

在多线程编程中一般线程的个数都大于cpu的核心数,而一个cpu核心在任意时刻都只能被一个线程使用,CPU通过时间片分配算法来循环执行线程,当前线程执行完一个时间片后会切换到下一个线程。但是,在切换前会需要保存上一个线程的状态,以便下次切换回这个线程时,可以再加载这个线程的状态。所以线程从保存到再加载的过程就是一次上下文切换。

CPU分配给各个线程的时间非常短,所以CPU通过不停地切换线程执行,让我们感觉多个线程是同时执行的,时间片一般是几到几十毫秒(ms)。windows系统时不断的变换的,linux系统时固定的。那么cpu每秒都几十次到上百次的线程切换,而每次切换都需要纳秒量级的时间。所以上下文切换对于系统来说意味着消耗大量的cpu时间。事实上上下文切换可能是操作系统中时间消耗最大的操作。

2.代码并发执行一定比串行执行快吗?

①:什么是串行执行

一个时间段内,执行一个任务的同时不能执行其他任务,只能等到第一个任务完成后才能进行第二个任务,就这样任务一个接一个的执行就是串行。

②:什么是并发执行

一个时间段内,多个任务可以同时执行,各自的互不影响。

③:并发执行一定比串行执行快吗?

一个时间段内,串行执行是任务一个个的执行,并发执行是多个任务同时执行,那么并发执行一定比串行执行快吗?
首先定义一个任务,我们让两个线程去同时执行!

public class ConcurrencyTest {
    private static final long count = 10000L;

    public static void main(String[] args) throws Exception{
        concurrentcy();;
        serial();
    }
    private static void concurrentcy() throws Exception {
        long start = System.currentTimeMillis();
        Thread thread = new Thread(() -> {
            int a = 0;
            for (long i = 0; i < count; i++) {
                a += 5;
            }
        });
        thread.start();
        int b = 0;
        for (long i = 0; i < count; i++) {
            b--;
        }
        long time = System.currentTimeMillis() - start;
        thread.join();
        System.out.println(String.format("concurrecy: %dms, b=%d", time, b));
    }

    private static void serial() {
        long start = System.currentTimeMillis();
        int a = 0;
        for (long i = 0; i < count; i++) {
            a += 5;
        }
        int b = 0;
        for (long i = 0; i < count; i++) {
            b --;
        }
        long time = System.currentTimeMillis() - start;
        System.out.println(String.format("serial: %dms, b=%d", time, b));
    }
}

执行结果:
在这里插入图片描述
当并发执行循环操作不超过百万次时,并发执行速度会比串行执行操作要慢。 但是一旦循环超过百万,那么明显并发执行的效率会更高!
那么造成这种情况的原因是什么呢?
由于我们使用的是多核cpu,thread线程和main线程分别会多核cpu的不同的内核当中运行。这两个任务就是并发执行,各自的互不影响,那么者就属于并发。但是我们要注意由于时间片一般是几到几十毫秒(ms)这点时间无论是在哪个线程当中都是不足以支撑任务执行10000次,那么必然会涉及到线程间的上下文切换。
在这里插入图片描述
在serial()方法当中,只有main线程指向a+=5和b–两个任务每个任务分别指向10000次,而且由于程序执行顺序的原因,b–的任务只能等待a++任务的完成,这两个任务就是典型的串行执行。 多核CPU在执行单线程任务时,通常不会发生线程间的上下文切换。 上下文切换主要发生在操作系统需要从一个线程切换到另一个线程时,这通常涉及保存当前线程的状态并恢复下一个线程的状态。然而,在单线程环境下,只有一个线程在执行,因此没有线程间的切换需求。
在这里插入图片描述
总结:
由于上下文切换涉及到保存当前任务的执行状态(如CPU寄存器的内容、程序计数器等),并将这些状态信息存储到内存中,然后加载下一个任务的执行状态到CPU中,使其能够继续执行。这个过程需要一定的时间,并且涉及到CPU和内存之间的数据传输,可能会产生额外的开销。频繁的上下文切换会消耗大量的CPU时间和内存资源,从而可能降低整体的执行效率。特别是在处理大量短任务或者任务之间的切换开销相对较大的情况下,并发执行会因为过多的上下文切换而比串行执行更慢。

三、减少上下文切换实战

减少上下文切换的方法: 无锁并发编程、CAS算法、使用最少线程和使用协程。
(1) 无锁并发编程: 多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同分段的数据。
(2) CAS算法: Java的Atomic包使用CAS算法来更新数据,而不需要加锁。
(3) 使用最少线程: 避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态。
(4) 使用协程: 在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。
多线程是无序的,但是协程是有序的,一个线程下边可以创建多个协程,多个协程之间会按照一定顺序交替执行。

四、减少上下文切换实战

第一步:使用命令显示正在运行的java进程的进行ID

这里有两种命令,我们可以使用ps或jps命令来查看所有Java程序进程。ps命令是用于显示当前进程状态的命令,而jps命令是Java Virtual Machine Process Status Tool的缩写,用于显示所有Java进程的进程ID。

//使用ps命令查看所有java程序进程
ps aux | grep java
//使用jps命令查看所有java程序进程
jps

在这里插入图片描述

第二步:使用jstack命令dump(镜像)线程信息

jstack 命令是JDK工具之一,使用该命令可以打印正在运行中 Java 进程的栈信息。
我们这里选择ID是5131的线程,我们首先要进入到jdk的bin目录当中,在执行jstack命令,生成5131.dump文件
在这里插入图片描述
在这里插入图片描述

第三步:通过各种状态的线程数量

grep java.lang.Thread.State 5131.dump | awk '{print $2$3$4$5}' | sort | uniq -c

在这里插入图片描述
注意我这里没有那么多线程,所有只能借助其他的信息
在这里插入图片描述
统计所有线程分别处于什么状态,发现300多个线程处于WAITING(onobject-monitor)状态。

第四步:打开dump文件,查看处于WAITING(onobjectmonitor)的线程在做什么

我们发现大量线程都闲着。
在这里插入图片描述

第五步: 减少工作线程数,将maxThreads设置小一点

在tonmcat的server当中改变最大线程数的数量,将其减少!
在这里插入图片描述

第六步: 重启

重启统计WAITING(onobjectmonitor)数量,发现减少了很多,WAITING的线程少了,系统上下文切换的次数就会少,因为每一次从WAITING到RUANNABLE都会进行一次上下文切换,可以用vmstat命令来查看上下文切换的次数,其中cs列就是指上下文切换的数目(一般情况下, 空闲系统的上下文切换每秒大概在1500以下)。
在这里插入图片描述

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

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

相关文章

ElasticSearch实战之项目搜索高亮

文章目录 1. 前情配置2、数据操作2.1 操作API2.2 数据入库 3. 高亮搜索3.1 方法封装3.2 高亮搜索 1. 前情配置 为满足ElasticSearch可在项目中实现搜索高亮&#xff0c;我们需要先做一些前情配置 导入ElasticSearch依赖 <dependency><groupId>org.springframewor…

怎么设置启用远程桌面? 如何让外网电脑远程本地内网?

如何远程控制电脑&#xff1f;最简单实用的方案是开启电脑系统自带的远程桌面功能&#xff0c;如果涉及跨网、内外网互通&#xff0c;可以同时用快解析内网映射外网。下面是方案的具体实施步骤&#xff0c;供大家参考。 怎么打开设置启用远程桌面&#xff1f; 1.在目标需要远…

【详细讲解CentOS常用的命令】

&#x1f308;个人主页: 程序员不想敲代码啊 &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共…

android 创建module

文章目的&#xff1a; 快速创建module并使用 创建步骤&#xff1a; 1 创建module 2 修改module下的build.gradle文件 3 修改清单文件中MainActivity属性&#xff0c;否则APP会因为有多个启动界面而崩溃 4 在主项目build.gradle引用该object Module 至此&#xff0c;可在APP中…

排序(五)——非比较排序+排序总结

1.非比较排序 我们前面讲的排序算法都是通过比较大小来进行排序的&#xff0c;他们都是比较排序。 像基数排序、计数排序和桶排序等都不是通过比较大小来排序的&#xff0c;是非比较排序&#xff0c;在这里我们讲一下其中的计数排序和基数排序&#xff0c;而桶排序实现起来太…

在k8s 中部署有状态服务MongoDB高可用集群详解(附带镜像)

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Kubernetes航线图&#xff1a;从船长到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、k8s简介 2、MongoDB介绍 3、为什么要…

网络爬虫软件学习

1 什么是爬虫软件 爬虫软件&#xff0c;也称为网络爬虫或网络蜘蛛&#xff0c;是一种自动抓取万维网信息的程序或脚本。它基于一定的规则&#xff0c;自动地访问网页并抓取需要的信息。爬虫软件可以应用于大规模数据采集和分析&#xff0c;广泛应用于舆情监测、品牌竞争分析、…

【 书生·浦语大模型实战营】作业(五):LMDeploy 量化部署

【 书生浦语大模型实战营】作业&#xff08;五&#xff09;&#xff1a;LMDeploy 量化部署 &#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系…

Vue2之组件通信(爆肝)

大家有什么想看的可以在评论区留言&#xff0c;我尽量满足&#xff0c;感谢大家&#xff01; 组件通信是vue中一个非常重要的内容&#xff0c;我们需要掌握好组件通信&#xff0c;那么让我为大家介绍几种组件通信的方式吧&#xff01; 一、props 这是父传子的方式&#xff0…

FFmpeg合并音视频文件操作备忘(mac版)

利用NDM嗅探插件从B站下载下来的文件是音视频分开的&#xff0c;用剪辑软件合并时发现导出时文件都特别大&#xff0c;于是使用FFmpeg处理 环境&#xff1a; MBP M1芯片版 系统 macOS Sonama 14.4.1 操作步骤&#xff1a; 一、官方下载链接&#xff1a;https://evermeet.cx/…

MySQL 锁机制全面解析

目录 1. MySQL的锁类型1.1 全局锁1.2 表锁1.3 行锁1.4 共享锁&#xff08;读锁&#xff09;1.5 排它锁&#xff08;写锁&#xff09;1.6 死锁 2 乐观锁和悲观锁2.1 乐观锁2.2 悲观锁 3 意向锁4 间隙锁5 临键锁6. 事务隔离级别对锁的影响6.1 读未提交&#xff08;Read Uncommitt…

npm内部机制与核心原理

npm 的核心目标&#xff1a; Bring the best of open source to you, your team and your company. npm 最重要的任务是安装和维护开源库。 npm 安装机制与背后思想 npm 的安装机制非常值得探究。Ruby 的 Gem&#xff0c;Python的pip都是全局安装机制&#xff0c;但是npm的安装…

️️️Vue3+Element-Plus二次封装一个可定制化的table组件

前言 为什么需要二次封装 开发后台管理系统,会接触到很多表格和表单,一但表格表单多起来,仅仅只需要一小部分改变&#xff0c;都需要在中重写一大堆代码,许多重复逻辑,我们可以把重复逻辑抽离出来二次封装一个组件 使用,减少在开发中需要编写的代码。 为什么需要定制化 每个…

【AI工具之Prezo如何自动生成PPT操作步骤】

先说优缺点&#xff1a; 最大的优点就是免费&#xff08;但说实话功能和体验方面很弱&#xff09;支持中文提问&#xff08;最好用英文&#xff09;&#xff0c;智能生成图文&#xff08;但是只能生成英文内容&#xff09;可以AI生成图片&#xff0c;图片很精美酷炫&#xff0…

数据可视化(四):Pandas技术的高级操作案例,豆瓣电影数据也能轻松分析!

Tips&#xff1a;"分享是快乐的源泉&#x1f4a7;&#xff0c;在我的博客里&#xff0c;不仅有知识的海洋&#x1f30a;&#xff0c;还有满满的正能量加持&#x1f4aa;&#xff0c;快来和我一起分享这份快乐吧&#x1f60a;&#xff01; 喜欢我的博客的话&#xff0c;记得…

(八)Pandas窗口数据与数据读写 学习简要笔记 #Python #CDA学习打卡

一. 窗口数据(Window Functions) Pandas提供了窗口函数(Window Functions)用于在数据上执行滑动窗口操作&#xff0c;可以对数据进行滚动计算、滑动统计等操作。需要注意的是&#xff0c;在使用窗口函数时&#xff0c;需要根据实际需求选择合适的窗口大小和窗口函数&#xff0…

硬件设备杂记——12G SDI及 AES67/EBU

常见的 SDI线缆规格&#xff0c;HD-SDI又被称为1.5G-SDI&#xff0c;具体参数以秋叶原的参数为例 AES67/EBU 目前音频网络标准主要集中在OSI网络体系的第二层和第三层。 第二层音频标准的弊端在于构建音频网络时需要专用的交换机&#xff0c;无法利用现有的以太网络&#xff0c…

布局香港之零售中小企篇 | 传承之味,迈向数字化经营的时代

随着内地与香港两地经贸合作日渐紧密&#xff0c;越来越多内地消费品牌将目光投向香港这片充满机遇的热土&#xff0c;纷纷入驻香港市场。「北店南下」蔚然成风&#xff0c;其中不乏已在内地市场深耕多年的传统老字号。数字化经营时代&#xff0c;老字号焕新刻不容缓&#xff0…

QoS流量整形

流量整形是一种带宽技术形式&#xff0c;它延迟某些类型的网络数据包的流动&#xff0c;以确保更高优先级应用程序的网络性能&#xff0c;它主要涉及调整数据传输速率&#xff0c;以确保网络资源以最佳容量得到利用。流量整形的目的是防止网络拥塞并提高网络的整体性能&#xf…

【Leetcode每日一题】 分治 - 排序数组(难度⭐⭐)(60)

1. 题目解析 题目链接&#xff1a;912. 排序数组 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 算法思路&#xff1a; 快速排序作为一种经典的排序算法&#xff0c;其核心思想在于通过“分而治之”的策略&#xff…