当前位置: 首页 > article >正文

多线程篇八

多线程篇八

如笔者理解有误欢迎指正交流🌸🌸🌸


线程池
什么是线程池?

顾名思义,线程池是一个存放了很多线程的池子.既然有很多线程,那一定很方便调用对吧,有很多线程那大家一定喜欢一起玩吧(并发).

线程池是一种并发编程中常用的技术,用于管理和重用线程.
线程池由线程池管理器、工作队列和线程池中的线程构成.

线程池的优点

由于进程的频繁创建和销毁带来的巨大开销,所以聪明的大佬们选择引入线程池或者更轻量级的协程(纤程).
协程的本质室程序员再用户态代码中进行调度,不依赖内核.
纯用户态代码是基于线程封装过来的就比内核调用更加安全.
而引入线程池就能减少每次启动、销毁线程的损耗.【用完了也不用销毁,多次利用,喜欢用一辈子的奥特乐袋子!(bushi】

标准库中线程池

img
Tips

corePoolSize: 核心线程数(一个线程池里,最少有多少个线程)
maximumPoolSize :最大线程数(一个线程池中,最多有多少个线程)
keepAliveTime:线程空闲超过这个时间阈值,就会被销毁
unit:时间单位,取分钟,秒,小时等等
workQueue:和定时器相同,线程池也可以有很多任务,也可以设置为带有优先级的
ThreadFactory: 线程工厂,本质上是给new这个操作封装了一层,可能同名同参数的构造方法,这样构成不了重载,我们就想弥补一下这个缺陷,封装一层构造方法.

拒绝策略【重点】

一个线程池能容纳的任务数量有限,当持续添加任务的时候可能会超出上限,这时候拒绝策略就闪亮登场了.
img

1.直接抛出异常,新任务和旧任务都罢工.
2.新任务由添加它的线程自己执行.
3.丢弃任务队列中最老的任务
4.丢弃当前新加的任务

Excutors创建线程的几种方式

newFixedThreadPool:创建固定数目的线程池
newCacheThreadPool:创建线程数目动态增长的线程池(构造出的线程池对象都能动态适应 需要添加新任务时线程会根据需要自动被创建出来 并且可以在池中保留一段时间)
newSingleThreadExcutor:创建只包含单个线程的线程池
newScheduledThreadPool:设定延迟时间的执行命令/定期执行命令(进阶版的定时器)

线程池的实现

上代码!

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ThreadPool {
    //用于保存线程,用于以后能取出线程并修改
    private List<Thread> ThreadList = new ArrayList<>();
    //用于保存任务的队列
    private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);

    //通过这个方法,把这个任务添加到线程池中.
    public void submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }

    //通过n指定创建多少个线程
    //创建了一个固定数量的线程池
    public ThreadPool(int n) {
        for(int i = 0; i < n; i++) {
            Thread t = new Thread(() -> {
                try {
                    //取出一个任务,并执行
                    Runnable runnable = queue.take();
                    runnable.run();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            t.start();
            ThreadList.add(t);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadPool pool = new ThreadPool(4);
        for(int i = 0; i < 1000; i++) {
            int n = i;
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    //要执行的工作
                    System.out.println("执行任务 " + n + ", 当前线程为: " + Thread.currentThread().getId());
                }
            });
        }
    }
}

使用线程池需要设置线程的数目为多少合适?
一个线程执行的代码主要分为两类
1.CPU密集型(主要逻辑是算术运算/逻辑判断)
2.IO密集型(主要是进行IO操作)

假设一个代码的所有代码都还是CPU密集型的这时线程池的数量不应该超过N(N是极限)设置比N更大这个时候久无法提高效率了.在 CPU满的情况下无法提高效率此时增加线程反而增加更多的线程开销.
如果一个线程的所有代码是IO密集的,此时不用CPU,此时设置的线程数就可能超过N.较大的值可以用一个核心通过线程调用的方式并发执行.

正确的思路:线程池的线程数目与代码密切相关 所以通过实验的方式进行性能测试将代码修改成符合预期的状态

补充
对比线程和进程
线程的优点

1.创建出一个新的线程比创建一个新进程的代价小得多.
2.与进程之间切换相比,线程之间切换很少需要OS
3.线程占用的资源更少(相比进程
4.可以充分利用多处理器的可并行数量
5.在等待IO操作结束的时候执行其他的计算任务
6.计算密集型应用,将计算分解到多个线程中实现
7.I/O密集型应用为了提高性能将I/O操作重置线程可以等待不同的I/O操作

进程和线程的区别

1.进程是系统进行资源分配和调度的最小单位(独立的)线程数是最小的执行单位
2.进程有自己的内存空间,线程值独享指令执行的必要资源(比如寄存器和栈)
3.由于同一进程的各线程共享内存和文件资源,可以不通过内核直接俄通信.
4.线程的创建切换及终止效率高.

保证线程安全的思路

)线程数是最小的执行单位
2.进程有自己的内存空间,线程值独享指令执行的必要资源(比如寄存器和栈)
3.由于同一进程的各线程共享内存和文件资源,可以不通过内核直接俄通信.
4.线程的创建切换及终止效率高.


未完待续⭐⭐⭐


http://www.kler.cn/a/324605.html

相关文章:

  • mysql中mvcc如何处理纯读事务的?
  • 如何让手机ip变成动态
  • Web导出Excel表格
  • 【Linux】Ubuntu中muduo库的编译环境安装
  • IDEA2024:右下角显示内存
  • rust高级特征
  • SpringBoot集成阿里easyexcel(二)Excel监听以及常用工具类
  • 阴影的基本原理
  • 梳理一下C语言中的格式说明符
  • uniapp js判断key是否在json中?
  • ArcgisEngine开发中,Ifeatureclass.Addfield 报错0x80040655处理方法
  • 0基础学习CSS(六)字体
  • python-list-comprehension-three-way-partitioning-array-around-given-range
  • iText 5 通过创建 Document 对象,并使用 PdfWriter 将内容写入 PDF 文件
  • ubuntu重新安装clickhouse
  • 前端面试题(九)
  • 【Mybatis】常见面试题汇总 共56题
  • 复试经验分享《一、问答题自测》(408、相关前沿技术)
  • 在Kali Linux VNC服务器上安装RDP服务
  • Android使用RecyclerView仿美团分类界面
  • 【JavaEE】——阻塞队列,生产消费者模型(较难)
  • BACnet协议-(基于ISO 8802-3 UDP)(2)
  • 【系统方案】智慧城市大数据平台建设方案(Word)
  • 【小程序websocket最佳实践,有心跳和断线重连】
  • JD面试题
  • huggingface实现中文文本分类