|
JavaEE
JavaEE——进程与线程的关系
JavaEE——No.2 多线程案例(内含线程池)
I/O
操作结束的同时, 程序可执行其他的计算任务I/O
操作重叠。线程可以同时等待不同的 I/O 操作进程 | 线程 |
---|---|
系统进行资源分配和调度的一个独立单位 | 线程是程序执行的最小单位 |
有自己的内存地址空间 | 只独享指令流执行的必要资源,如寄存器和栈 |
\ | 同一进程的各线程间共享内存和文件资源,可以不通过内核进行直接通信 |
创建、切换及终止效率较低 | 创建、切换及终止效率更高 |
在之前的文章中提过, 如果线程创建的速率进一步的频繁了, 此时线程创建销毁的开销仍然不能忽略.
此时, 我们用线程池
来进一步优化这里的速度. 在一个池子中创建好很多线程, 当需要执行任务的时候, 不需要重新创建线程了, 只需要直接从池子里取一个现成的线程, 直接使用. 用完, 也不必释放线程, 而是直接还回到线程池里.
那么为什么从池子里取, 要比创建新线程快呢?
用户态
-> 内核态
的切换操作, 这个操作是存在一定的开销的如图: 我们的计算机大概是这样的结构
应用程序发起的一个 创建线程 的行为, 线程本质上是 PCB, 是内核中的数据结构.
- 应用程序就需要通过系统调用, 进入操作系统内核中执行
- 内核完成 PCB 的创建, 把 PCB 加入到调度队列中, 然后再返回给应用程序
用户态
实现的逻辑.
# 注意 #
创建进程, 也是通过内核完成的. 创建线程和创建进程都要经历 用户态 -> 内核态, 这个过程
- 用户态, 每个进程都是自己执行自己的逻辑
- 内核态, 一个系统里只有一份内核再执行逻辑, 这个内核要给所有的进程都执行一些服务
总结: 使用线程池是纯用户态
操作, 要比创建线程 (经历内核态的操作) 要快.
相关参数解释
标准库中的拒绝策略
比如:
外卖员是一个线程池, app 给外卖员安排任务. 任务已经很多了, 外卖员已经送不完了. 超时要扣钱了, 外卖员哇的一声就哭了, 不干了, 罢工了.
比如:
还是这个外卖员, app 安排的工作过多, 做不了了, 外卖员让 app 自己干. 如果 app 自己能干, 他就自己干了, 如果 app 不干, 就丢弃任务.
比如:
外卖员现在要送三个外卖: 外卖1, 外卖2, 外卖3. 这是又接到一单, 外卖4. 外卖员做不了. app 发消息通知外卖员, 外卖1 不着急, 先送 外卖4.
比如:
外卖员现在要送三个外卖: 外卖1, 外卖2, 外卖3. 这是又接到一单, 外卖4. 外卖员做不了. app 发消息通知外卖员, 外卖4 不着急, 还是继续先送 外卖1.
线程池可以自定义线程数目, 那在实际开发中, 线程池的线程数目, 如何确定 ?
在这里是不好确定出具体个数的, 因为
- 主机的 CPU 的配置, 不确定
- 程序的执行特点, 不确定
有些程序代码急需要进行很多 CPU
密集型任务, 有需要很多 IO
任务.
如果任务 100% 是 CPU 密集型的话, 线程数目最多也就是 N
, 更大就没意义了, CPU 已经被占满了.
如果任务 10% 是 CPU 密集型, 90% 都在操作 IO , 线程数目设置成 10N
也是没关系的.
(在工作中实际的处理方案, 是进行试验验证, 针对程序进行性能测试, 分别给线程池设置成不同的数目, 分别记录每种情况下, 程序的一些核心性能指标和系统负载情况)
|
以上就是今天要讲的内容了,希望对大家有所帮助,如果有问题欢迎评论指出,会积极改正!!