java 自定义单线程池 java创建自定义线程池_创建线程

线程池

2.1 线程池思想

我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:
如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。
那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?
在Java中可以通过线程池来达到这样的效果。今天我们就来详细讲解一下Java的线程池。

2.2 线程池概念

概念:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。

由于线程池中有很多操作都是与优化资源相关的,我们在这里就不多赘述。我们通过一张图来了解线程池的工作原理:

java 自定义单线程池 java创建自定义线程池_创建线程_02

合理利用线程池能够带来三个好处

  1. 降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
  2. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  3. 提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

2.3 线程池的使用

2.3.1 概述

Java里面线程池的顶级接口是java.util.concurrent.Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是java.util.concurrent.ExecutorService

要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在java.util.concurrent.Executors线程工厂类里面提供了一些静态工厂,生成一些常用的线程池。官方建议使用Executors工程类来创建线程池对象。

java 自定义单线程池 java创建自定义线程池_java_03

3.3.2 代码实现

3.3.2.1 基于Executors类创建线程静态方法实现

Executors类中有个创建线程池的方法如下:

方法名

描述

public static ExecutorService newFixedThreadPool(int nThreads)

创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变化,适用于负载较重的场景,对当前线程数量进行限制。(保证线程数可控,不会造成线程过多,导致系统负载更为严重)

public static newCachedThreadPool()

用来创建一个可以无限扩大的线程池,适用于负载较轻的场景,执行短期异步任务。(可以使得任务快速得到执行,因为任务时间执行短,可以很快结束,也不会造成cpu过度切换)

public static newSingleThreadExecutor

创建一个单线程的线程池,适用于需要保证顺序执行各个任务。

public static newScheduledThreadPool

适用于执行延时或者周期性任务。

//使用线程池进行多线程代码执行
public class ExecutorsTest {
    public static void main(String[] args) {
        //1获取线程池对象
        //通过Executors工具类对应的静态方法 创建对应的线程池对象
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        //2创建执行的任务对象
        Runnable r=new Runnable() {
            @Override
            public void run() {
                //获取当前线程
                Thread thread = Thread.currentThread();
                System.out.println(thread.getName()+"执行了任务");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(thread.getName()+"任务执行完毕,回归线程池");
            }
        };
        //3向线程池提交任务
        executorService.submit(r);
        executorService.submit(r);
        executorService.submit(r);

        //4关闭线程池
        executorService.shutdown();
    }
}

java 自定义单线程池 java创建自定义线程池_线程池_04

3.3.2.2基于ThreadPoolExecutor自定义线程池填入参数实现

ThreadPoolExecutor核心参数

Executor是线程池的顶级接口,接口中只定义了一个方法 void execute(Runnable command);线程池的操作方法都是定义子在ExecutorService子接口中的,所以说ExecutorService是线程池真正的接口。

ThreadPoolExecutor重要参数:

public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {}


- corePoolSize: 线程池核心线程数
- maximumPoolSize:线程池最大数
- keepAliveTime: 空闲线程存活时间
- unit: 时间单位
- workQueue: 线程池所使用的缓冲队列
- threadFactory:线程池创建线程使用的工厂
- handler: 线程池对拒绝任务的处理策略

线程池四种拒绝策略

线程四种拒绝策略,当工作任务大于最大线程 + 阻塞队列会执行阻塞队列。

拒绝策略类型

说明

1

ThreadPoolExecutor.AbortPolicy

默认拒绝策略,拒绝任务并抛出任务

2

ThreadPoolExecutor.CallerRunsPolicy

使用调用线程直接运行任务

3

ThreadPoolExecutor.DiscardPolicy

直接拒绝任务,不抛出错误

4

ThreadPoolExecutor.DiscardOldestPolicy

触发拒绝策略,只要还有任务新增,一直会丢弃阻塞队列的最老的任务,并将新的任务加入

public class MyThreadPoolTest {
    public static void main(String[] args) {
        //就是通过创建ThreadPoolExecutor对象 调用构造方法传入参数实现自定义线程池
        //如果想对线程池添加额外功能可以通过继承ThreadPoolExecutor类 实现
        //但是必须通过构造方法传入参数 才能实现线程池功能
        int initSize=3;//初始化线程池中线程个数
        int maxSize=5;//任务提交后没有空闲线程 扩容后线程池中线程最大个数
        int keepTime=0;//线程池中线程最大空闲时间(超过后会回收,直至线程数到达初始化大小)0代表不回收
        TimeUnit timeUnit=TimeUnit.MILLISECONDS;//空闲时间单位 毫秒,枚举类型TimeUnit.SECONDS代表分钟
        BlockingQueue<Runnable> queue=new LinkedBlockingQueue<>();
        ThreadFactory threadFactory=Executors.defaultThreadFactory();//默认线程创建工厂
        RejectedExecutionHandler handler= new ThreadPoolExecutor.AbortPolicy();//默认拒绝策略
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(initSize, maxSize, keepTime, timeUnit, queue, threadFactory, handler);

        Runnable r=new Runnable() {
            @Override
            public void run() {
                //获取当前线程
                Thread thread = Thread.currentThread();
                System.out.println(thread.getName()+"执行了任务");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(thread.getName()+"任务执行完毕,回归线程池");
            }
        };

        threadPoolExecutor.submit(r);
        threadPoolExecutor.submit(r);
        threadPoolExecutor.submit(r);


        threadPoolExecutor.shutdown();
    }
}

java 自定义单线程池 java创建自定义线程池_java_05