深入理解并发和线程

本文介绍了进程的基本概念,包括其在操作系统中的作用和资源管理;详细阐述了线程的概念、与进程的关系以及线程通信的方式。还探讨了CPU核心数与线程数的关系,上下文切换的原理和成本,以及并行和并发的区别。此外,文中还比较了线程启动的不同方式,并讨论了线程终止的几种方法,如自然终止、stop和中断。
摘要由CSDN通过智能技术生成

进程和线程

进程

        当运行一个应用程序时, 操作系统就会启动进程, 执行程序的代码, 将指令加载到CPU,数据加载到内存,指令运行过程中还需要用到磁盘、网络等设备.简单说就是加载指令、管理内存、管理 IO.大多数程序可以开启多个进程, 例如记事本, 浏览器开多窗口.在操作系统角度, 进程是分配资源的最小单位.

线程

        线程必须依赖进程存在, 线程是进程的一个实体, 是CPU调度的最小单位.一个进程可以拥有多个线程, 一个线程必须依赖一个主进程.线程自己没有系统资源权限, 只有运行必要的栈, 寄存器, 程序计数器, 它可以和同属于一个进程的线程共享所有资源.线程也被叫轻量级进程.

进程间通信

        同计算机的进程通信称为IPC,不同计算机进程间通信叫RPC, 需要通过网络, 共同遵守的协议.像Dubbo就是一个RPC框架, http协议也经常用在RPC.

进程通信方式

  • 管道
  • 信号
  • 消息队列
  • 共享内存
  • 信号量
  • 套接字

CPU核心数与线程数

        同一时刻, 一个CPU核心只能执行一个线程, Intel引入超线程技术后, 有了逻辑核的概念, 一个物理核心有两个逻辑核, 例如四核的机器, 有八个逻辑核, 同一时刻能运行8个线程.

        在java里面, Runtime.getRuntime().availableProcessors()可以获取当前系统逻辑核数,可以用这个方法设置线程池核心数.

上下文切换

        计算机的CPU是有限的, 操作系统需要在多个线程间调度,每个线程需要使用CPU的资源(寄存器, 程序计数器), 为保证程序在多线程切换过程中正常执行, 就有了上下文的概念.

上下文:

        从代码角度, 是线程在方法执行中的局部变量

        从JVM角度, 是栈上存的信息

切换过程:

  1. 暂停当前线程, 并保存上下文
  2. 从队列中选择下个执行线程
  3. 读取下个线程需要的上下文, 从CPU寄存器中恢复它
  4. 返回到下个线程上次中断的位置, 从程序计数器中读取, 恢复线程

上下文切换成本:

        一次上下文切换大概需要5000~20000个时钟周期, 一个简单计算指令几个乃至十几个左右的时钟周期.

监控上下文切换

  • vmstat: 系统整体上下文切换面板
  • pidstat: 进程级别上下文切换面板

并行和并发

        并行: 比如浏览器同时打开两个窗口看视频, 叫做并行

        并发: 并发一般会带上时间一起说, 比如在秒杀场景中, 一秒内有一万人下单

线程启动

  1. 继承Thread类, 调start方法
  2. 实现runable接口, 传到Thread类, 调start方法
  3. 实现callable接口(有返回值), 传入FutureTask类(因为Thread构造方法不支持callable, FutureTask实现了runable接口), 再传到Thread类, 调start方法

启动线程有几种方式?

        两种, 一种是派生自Thread类,另一种是实现Runnable接口.callable底层也是用FutureTask实现runable接口, 而线程池是一种池化技术, 管理线程的生命周期而已, 类似数据库连接池.

run和start区别?

        run是当前线程执行task任务, 不能利用异步

        start是调用操作系统的native的start0方法, 会进入一个队列等待操作系统分配CPU, 等分配到CPU后才会真正执行run方法, 异步.如果多次调一个线程的start方法会抛出异常.

线程终止

自然终止

        run方法全部跑完或者抛异常未捕获

stop

        暂停、恢复和停止操作对应在线程Thread的API就是suspend()、resume()和stop(), 已过期.

        suspend: 调用后线程不会释放资源, 例如锁, 而是占着资源进入睡眠状态, 容易造成死锁问题

        stop: 调用后线程强制终止, 没有机会释放资源, 可能造成文件损坏问题

中断

  1. thread.interrupt(): 给线程打上中断标识
  2. thread.isInterrupted(): 判断线程是否有中断标识
  3. Thread.interrupted(): 判断线程是否有中断标识, 判断完后给中断标识设置成false, 注意抛中断异常也会给中断标识设置成false

        不建议手动加字段去设置中断标识, 有延迟和阻塞问题, 例如sleep, take方法阻塞时, 能自动检测到中断标识, 抛出中断异常.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值