多线程 (九) 线程池的使用及实现

点进来你就是我的人了
博主主页:戳一戳,欢迎大佬指点!

人生格言:当你的才华撑不起你的野心的时候,你就应该静下心来学习!

欢迎志同道合的朋友一起加油喔
目标梦想:进大厂,立志成为一个牛掰的Java程序猿,虽然现在还是一个嘿嘿
谢谢你这么帅气美丽还给我点赞!比个心


目录

 一.线程的概念

二、创建线程池的方式

三.线程池的创建(工厂模式创建)

四.线程池工作原理及参数

五. 四种拒绝策略

六.自定义一个线程池



 一.线程的概念

线程池:一个容纳多个线程的容器,容器中的线程可以重复使用,省去了频繁创建和销毁线程对象的操作。

线程池作用:

  • 降低资源消耗,减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
  • 提高响应速度,当任务到达时,如果有线程可以直接用,不会出现系统僵死。
  • 提高线程的可管理性,如果无限制的创建线程,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

线程池的核心思想:线程复用,同一个线程可以被重复使用,来处理多个任务。

池化技术 (Pool) :一种编程技巧,核心思想是资源复用,在请求量大时能优化应用性能,降低系统频繁建连的资源开销。

为什么从线程池取线程要比从系统申请效率更高呢

因为从线程池取线程是纯粹的用户态操作

从系统创建线程,涉及到内核态和用户态的切换

内核态用户态是什么?

操作系统对程序的执行权限进行分级,分别为用户态和内核态。用户态相比内核态有较低的执行权限,很多操作是不被操作系统允许的,简单来说就是用户态只能访问内存,防止程序错误影响到其他程序,而内核态则是可以操作系统的程序和普通用户程序

内核态: cpu可以访问计算机所有的软硬件资源

用户态: cpu权限受限,只能访问到自己内存中的数据,无法访问其他资源

为什么要有用户态和内核态?
系统需要限制不同的程序之间的访问能力,防止程序获取不相同程序的内存数据,或者外围设备的数据,并发送到网络,所有cpu划分出两个权限等级用户态和内核态

举个简单的例子加深理解

一位滑稽老铁去银行取钱,如果自己操作ATM机取钱效率很高,如果让工作人员去帮忙取钱,此时他可能在取钱的过程中先接杯水,再和别人唠会嗑啥的,效率会很低!

这里的滑稽老铁就是用户态,工作人员就是内核态,滑稽老铁自己取钱相当于线程池取线程,是纯用户态的操作,而交给工作人员去取钱相当于向系统申请资源创建线程,涉及到到内核态和用户态的切换

二、创建线程池的方式

线程池的创建⽅式总共包含以下 7 种(其中 6 种是通过 Executors 创建的, 1 种是通过

ThreadPoolExecutor 创建的):

        1. Executors.newFixedThreadPool:创建⼀个固定⼤⼩的线程池,可控制并发的线程数,超出的线程会在队列中等待;

        2. Executors.newCachedThreadPool:创建⼀个可缓存的线程池,若线程数超过处理所需,缓存⼀段时间后会回收,若线程数不够,则新建线程;

        3. Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执⾏顺序;

        4. Executors.newScheduledThreadPool:创建⼀个可以执⾏延迟任务的线程池;

        5. Executors.newSingleThreadScheduledExecutor:创建⼀个单线程的可以执⾏延迟任务的线程池;

        6. Executors.newWorkStealingPool:创建⼀个抢占式执⾏的线程池(任务执⾏顺序不确定)【JDK1.8 添加】。

        7. ThreadPoolExecutor:最原始的创建线程池的⽅式,它包含了 7 个参数可供设置,后⾯会详细讲。

三.线程池的创建(工厂模式创建)

多线程 (九) 线程池的使用及实现_第1张图片

 工厂模式实际上就是拿来填构造方法的坑的

例如当我们算一个坐标的时候,我们可以通过横纵坐标构造一个点,也可以通过极坐标的方式构造一个点,但是在构造的时候我们发现两种的参数是一样的,无法构成重载

于是就可以利用工厂模式构建一个工厂类,搞两个普通的方法重载去实现,问题就能得到解决

伪代码演示:

//构造方法方法冲突
class  Point{
public Point(double x,double y)

}

public  Point(double r,double a){
}

}

//创建一个工厂类
class  PointBuilder{
public static point getPointA(double x,double y)

}

public  static point getPointB(double r,double a){
}

}

四.线程池工作原理及参数

多线程 (九) 线程池的使用及实现_第2张图片

 Executors类提供4个静态工厂方法:newCachedThreadPool()、newFixedThreadPool(int)、newSingleThreadExecutor和newScheduledThreadPool(int)。这些方法最终都是通过ThreadPoolExecutor类来完成的,这里强烈建议大家直接使用Executors类提供的便捷的工厂方法,能完成绝大多数的用户场景,当需要更细节地调整配置,需要先了解每一项参数的意义。

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}
  1. corePoolSize(线程池基本大小)必须大于或等于0;
  2. maximumPoolSize(线程池最大大小)必须大于或等于1;
  3. maximumPoolSize必须大于或等于corePoolSize;
  4. keepAliveTime(线程存活保持时间)必须大于或等于0;
  5. workQueue(任务队列)不能为空;
  6. threadFactory(线程工厂)不能为空,默认为DefaultThreadFactory类
  7. handler(线程饱和策略)不能为空,默认策略为ThreadPoolExecutor.AbortPolicy。

五. 四种拒绝策略

多线程 (九) 线程池的使用及实现_第3张图片

CallerRunsPolicy呼叫着运行策略,通常叫做,调用者运行策略:是如果线程池的线程全部被用完的时候,会把多余的任务返回给调用者去执行;(敢于反驳,我干不了了,就把任务丢给发布任务的人去干,哈哈哈,打工人要学学,不能一味的屈服)
AbortPolicy终止策略:如果线程池线程被用完了,直接抛出异常 rejectedExecution从而终止任务;
DiscardPolicy丢弃策略:如果线程池的线程被用完了,不抛出异常,直接丢弃多余的任务;(很有脾气是吧,我干不了我不干,我也不吭气,直接仍了,哈哈哈)
DiscardOldestPolicy丢弃最老策略:如果线程池的线程被用完了,就把等待时间最久的任务丢弃掉;(这是不是工作中,把一些棘手的任务放到最后,一直到发布任务的人忘记了有这么一回事了,然后我们也可以不干了,哈哈哈哈)

六.自定义一个线程池

多线程 (九) 线程池的使用及实现_第4张图片

//自定义一个线程池
class MyThreadPool {
    //阻塞队列用来存放任务
    private BlockingQueue queue =new LinkedBlockingDeque<>();

    public void submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }
    //此处实现一个固定线程数的线程池
    public MyThreadPool(int n) {
        for (int i = 0; i < n; i++) {
            Thread t =new Thread(() -> {
                    try {
                        while (true) {
                            //取任务
                            Runnable runnable = queue.take();
                            runnable.run();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
            });
            t.start();
        }
    }
}
public class ThreadDemo1 {
    public static void main(String[] args) throws InterruptedException {
        MyThreadPool myThreadPool =new MyThreadPool(10);
        for (int i = 0; i < 1000; i++) {
            int number =i;
            myThreadPool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("hello "+number);
                }
            });
        }
    }
}

你可能感兴趣的:(java,jvm,开发语言)