并发基础知识

本文介绍了Java并发基础知识,包括进程与线程的概念、关系及其在高并发场景下的应用。详细讨论了线程的产生原因、JVM的内部线程以及并发、并行、串行的区别,同步异步、阻塞非阻塞的概念,并探讨了高并发的相关指标,如QPS、带宽等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

并发简述

​ Java在设计之初,就是支持多线程的语言。

​ 在Java学习中,我们经常能听到:高并发、多线程这样的词汇。那么,高并发是什么?线程是什么?高并发与线程有什么关系呢?
​ 那么为什么有进程,又为什么有线程呢?

​ 随着结束的发展,我们的CPU、内存、I/O设备不断迭代,不断朝着更快的方向努力。但是这三者有个核心的矛盾:速度的差异。CPU和内存的速度差异可以描述为:CPU天上一天,而内存地上一年(假设CPU执行一条普通指令需要一天,那么CPU读写内存需要等待一年)。内存和I/O设备的速度差异更大,内存天上一天,I/O设备地上十年。

​ 我们程序大部分都语句需要访问内存,有些还需要访问I/O。根据木桶理论,我们程序的整体性能取决于最慢的操作,也就是读写I/O设备。

​ 为了合理利用CPU的高性能,提高这三者的速度,计算机体系结构、操作系统、编译程序都做出了努力:

  • ​ CPU增加了缓存,均衡与内存的速度差异
  • ​ 操作系统增加了进程、线程,以分时复用CPU,进而均衡CPU与I/O设备的速度差异
  • ​ 编译程序优化指令执行次序,使缓存能够得到更加合理的利用


线程与进程

​ 在oracle的官方文档中,对进程与线程是这样描述的:

在这里插入图片描述

​ 翻译过来,就是进程,是通过fork命令创建出来的运行环境,包含了如文件描述符、用户ID等信息,它被设置为运行程序。进程是系统进行资源分配和调度的基本单位,进程作为程序独立运行的载体,可以保障程序正常执行。

​ 线程,是进程上下文中执行的一系列指令。

进程

​ 那么理解下,进程是程序的一次执行。当我们打开某个程序,就会产生一个进程。

​ 打开任务管理器,就可以看到:
在这里插入图片描述

​ 那么再理解下,我们下载了一个程序,但是没有打开。这个时候程序只是占用了一定的空间,大部分是磁盘。当我们打开这个程序,它才会耗费一定的CPU、内存等。如果我们的进程占用资源过大,系统为了响应我们的进程,就会造成卡顿。(例如电脑卡了,打开资源管理器,哦吼,某个进程占用CPU99.99999%)

​ 看到过一个很好的比喻:进程是对我们代码的一个实例化。

线程

​ 进程可以看做线程的容器。进程是程序的运行环境,而真正去执行程序的,是一个个线程。

​ 需要注意的是,Java的线程与操作系统的线程是一一对应的。

为什么有线程

​ 在计算机的发展历史中,是先存在的进程。随着计算机的发展,计算机的处理速度远远大于外设的处理速度,为了避免等待造成的浪费,提高程序的执行效率,才出现的线程。

JVM的自有线程

​ 我们随便写个测试函数,然后debug看一下:

   @Test
    public void test(){
        new Thread(()-> System.out.println("=================new thread=================")).start();
        System.out.println("==================sleeping==================");
    }

debug的线程情况如下所示,可以看到除了主线程外,还有几个jvm的自有线程:

Signal Dispatcher:把操作系统发来的信号分发给适当的处理程序

Finalizer:在学习垃圾回收的时候学到过,如果对象实现了finalize方法,就会加入到一个队列中,然后由JVM创建的低优先级的线程去执行,就是这个线程

ReferenceHandler:是JVM创建的优先级最高的守护线程,作用是在垃圾回收的时,ReferenceHandler主要作用是对需要回收的对象进行后序的回收清理工作。

部分源码:

		Thread handler = new ReferenceHandler(tg, "Reference Handler");
        /* If there were a special system-only priority greater than
         * MAX_PRIORITY, it would be used here
         */
        handler.setPriority(Thread.MAX_PRIORITY);
        handler.setDaemon(true);
        handler.start();

线程与进程的关系

进程线程
起源不同先有进程因为计算机的处理速度远远大于外设的处理速度,为了提高CPU利用率,才出现的线程
概念不同具有独立功能的程序运行起来的环境,是个实例,是系统分配资源与调度的单位CPU的基本调度单位
内存共享方式不同不同的进程之间的内存通常是不共享的线程之间,是有共享内存的
用有资源不同共享
1.进程代码段(重点)
2.进程的公有数据
3.进程打开的文件描述符
4.信号处理器
5.进程当前的目录
6.进程用户ID与进程组ID
私有:
1.线程ID
2.寄存器组的值
3.线程的堆栈(重点)
4.错误返回码
5.线程的信号屏蔽码
数量不同一个进程可以有多个线程,至少一个
开销不同1.线程的创建、终止时间比进程短
2.同一个进程内的线程切换时间比进程切换时间短
3.同一个进程的各个线程之间共享内存与文件资源,可以不同过内核进行通信
线程更轻量级

并发、并行、串行

​ 下面这张图就可以表示出这三者的区别(非原创,从慕课网视频截取):

在这里插入图片描述

这里用生活中的现象举个例子,假设我们有3个小伙伴住在同一间房。

串行

​ 这个屋子里只有一个浴室,那么三个小伙伴只能排队,一个洗完了另外一个才能去。

并发

​ 屋子里只有一个浴室跟一个厨房还有一台电脑。三个小伙伴商量了一下,小伙伴A去洗澡,B去做饭吃饭,C去打游戏;然后A去吃饭,B去打游戏,C去洗澡;最后A去打游戏,B去洗澡,C去吃饭。

并行

​ 这个屋子里有三个卧室,三个小伙伴一人一间,夜晚来了他们都在睡觉。


同步异步、阻塞非阻塞

​ 其实同步异步、阻塞非阻塞是两个维度的事情:

​ 同步异步指的是被调用者是否主动告诉调用者结果

​ 阻塞非阻塞指的是我作为调用者,在结果返回前能不能做别的事情

举个栗子来理解下。

​ 到吃饭的时间了,你肚子有点饿了,而这个时候你妈妈在厨房做饭。

同步

​ 如果你妈妈会主动告诉你饭好了,快来吃吧!这就是同步。

异步

​ 如果你妈妈在生你的气不想搭理你,饭好了就端上桌自己吃,也不喊你,等你闻到香味,或者饿得受不了了去饭桌上一看,诶饭好了,可以吃了!这就是异步。

阻塞

​ 如果你就蹲在厨房门口,饭不好你就不走了,啥事儿也不干了,这就是阻塞。

非阻塞

​ 如果你决定看会电影等饭,这就是非阻塞。


高并发

高并发:同时有很多请求发给服务器

​ 还是上面的例子。

​ 今天游戏出新英雄玛西了,三个小伙伴都非常急想去玩一下,都在急着抢电脑。

高并发与多线程的关系

​ 多线程只是解决高并发的一种手段,但不是唯一的方法。比如上面的栗子中我们可以加一台电脑(扩容?),如果是数据库的高并发,我们可以加缓存等。

高并发的指标

​ 还是上面几个小伙伴抢着玩电脑的栗子:

QPS

​ 每秒查询/请求数

​ 同一时刻有多少个小伙伴过来抢电脑

带宽
PV(PageView)

​ 综合浏览量

​ 这一台电脑一天内的试用次数

UV(UniqueVisitor)

​ PV基础上的去重

​ 这一台电脑一天内被几个小伙伴使用,一天内一人只算一次

并发连接数

​ 同一时间内有几个小伙伴可以玩电脑

服务器平均请求等待时间

​ 这几个小伙伴平均等待了多久就可以玩到电脑了~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值