线程池工作

线程池实现原理

当向线程池提交一个任务之后,线程池的处理流程如下:

1、判断是否达到核心线程数,若未达到,则直接创建新的线程处理当前传入的任务,否则进入下个流程
2、线程池中的工作队列是否已满,若未满,则将任务丢入工作队列中先存着等待处理,否则进入下个流程
3、是否达到最大线程数,若未达到,则创建新的线程处理当前传入的任务,否则交给线程池中的饱和策略进行处理。
流程图如下:
在这里插入图片描述

线程池的构造方法

实现类是:java.util.concurrent.ThreadPoolExecutor,主要构造方法:

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

corePoolSize:核心线程大小,当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使有其他空闲线程可以处理任务也会创新线程,等到工作的线程数大于核心线程数时就不会在创建了。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前把核心线程都创造好,并启动

maximumPoolSize:线程池允许创建的最大线程数。如果队列满了,并且以创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。如果我们使用了无界队列,那么所有的任务会加入队列,这个参数就没有什么效果了

keepAliveTime:线程池的工作线程空闲后,保持存活的时间。如果没有任务处理了,有些线程会空闲,空闲的时间超过了这个值,会被回收掉。如果任务很多,并且每个任务的执行时间比较短,避免线程重复创建和回收,可以调大这个时间,提高线程的利用率

unit:keepAliveTIme的时间单位,可以选择的单位有天、小时、分钟、毫秒、微妙、千分之一毫秒和纳秒。类型是一个枚举java.util.concurrent.TimeUnit

workQueue:工作队列,用于缓存待处理任务的阻塞队列,常见的有4种,本文后面有介绍

threadFactory:线程池中创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字

handler:饱和策略,当线程池无法处理新来的任务了,那么需要提供一种策略处理提交的新任务,默认有4种策略

线程池的使用步骤:

1、调用构造方法创建线程池
2、调用线程池的方法处理任务execute()
3、关闭线程池shutdown()/shutdownNow()

demo例子

package com.example.demo.demo.threadPoolDemo;

import java.util.concurrent.*;

/**
 * 线程池demo
 * 实现类是:java.util.concurrent.ThreadPoolExecutor
 *  public ThreadPoolExecutor(int corePoolSize,
 *                               int maximumPoolSize,
 *                               long keepAliveTime,
 *                               TimeUnit unit,
 *                               BlockingQueue<Runnable> workQueue,
 *                               ThreadFactory threadFactory,
 *                               RejectedExecutionHandler handler) {
 *     }
 */
public class ThreadPoolDemo {
    //线程池里占据最大数量为3
    static ThreadPoolExecutor executor = new ThreadPoolExecutor(3,
                        5, 10L, TimeUnit.SECONDS,
                        new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory(),
                        new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) {
        for (int i = 0; i <10 ; i++) {
            int j =i;
            String task = "任务"+j;
            executor.execute(()->{
//                模拟线程池运作
                try {
                    TimeUnit.SECONDS.sleep(j);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+task+"任务结束");
            });
        }
        executor.shutdown();
    }

}

设置线程池数量为3,只要三个线程在运行

pool-1-thread-1任务0任务结束
pool-1-thread-2任务1任务结束
pool-1-thread-3任务2任务结束
pool-1-thread-1任务3任务结束
pool-1-thread-2任务4任务结束
pool-1-thread-3任务5任务结束
pool-1-thread-1任务6任务结束
pool-1-thread-2任务7任务结束
pool-1-thread-3任务8任务结束
pool-1-thread-1任务9任务结束

线程池中常见5种工作队列

任务太多的时候,工作队列用于暂时缓存待处理的任务,jdk中常见的5种阻塞队列:

ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按照先进先出原则对元素进行排序

LinkedBlockingQueue:是一个基于链表结构的阻塞队列,此队列按照先进先出排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool使用了这个队列。

SynchronousQueue :一个不存储元素的阻塞队列,每个插入操作必须等到另外一个线程调用移除操作,否则插入操作一直处理阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用这个队列

PriorityBlockingQueue:优先级队列,进入队列的元素按照优先级会进行排序

SynchronousQueue队列的线程池demo

package com.example.demo.demo.threadPoolDemo;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 线程池中队列:SynchronousQueue
 * 静态工厂方法Executors.newCachedThreadPool使用这个队列
 *  public static ExecutorService newCachedThreadPool() {
 *         return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
 *                                       60L, TimeUnit.SECONDS,
 *                                       new SynchronousQueue<Runnable>());
 *     }
 */
public class ThreadPoolDemo2 {
    static ExecutorService excutor =  Executors.newCachedThreadPool();//队列SynchronousQueue

    public static void main(String[] args) {
        for (int i = 0; i <10 ; i++) {
            int j =i;
            String tackName = "任务"+j;
            excutor.execute(()->{
                try {
                    TimeUnit.SECONDS.sleep(j);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+tackName+"任务结束");
            });

        }
        excutor.shutdown();
    }
}

pool-1-thread-1任务0任务结束
pool-1-thread-2任务1任务结束
pool-1-thread-3任务2任务结束
pool-1-thread-4任务3任务结束
pool-1-thread-5任务4任务结束
pool-1-thread-6任务5任务结束
pool-1-thread-7任务6任务结束
pool-1-thread-8任务7任务结束
pool-1-thread-1任务8任务结束
pool-1-thread-9任务9任务结束

线程池内部方法

ThreadPoolExecutor内部提供了几个方法beforeExecute、afterExecute、terminated

package com.example.demo.demo.threadPoolDemo;

import java.util.concurrent.*;

/**
 * ThreadPoolExecutor
 * 线程池自带的方法
 */
public class ThreadPoolDemo3 {

    public static class ThreadT1  implements  Runnable{
        String taskName;

        public ThreadT1(String taskName) {
            this.taskName=taskName;
        }
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"正在处理"+this.taskName);
        }

        @Override
        public String toString() {
            return "ThreadT1{" +
                    "taskName='" + taskName + '\'' +
                    '}';
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(10,10,10L,
                TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10), Executors.defaultThreadFactory(),(r, executors) -> {
            System.out.println("无法执行的任务"+r.toString());
        }){
            @Override
            protected void beforeExecute(Thread t, Runnable r) {
                super.beforeExecute(t, r);
                System.out.println(System.currentTimeMillis() + "," + t.getName() + ",开始执行任务:" + r.toString());
            }

            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                super.afterExecute(r, t);
                System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName() + ",任务:" + r.toString() + ",执行完毕!");
            }

            @Override
            protected void terminated() {
                super.terminated();
                System.out.println(System.currentTimeMillis() + "," + Thread.currentThread().getName() + ",关闭线程池!");

            }
        };
        for (int i = 0; i <10 ; i++) {
            executor.execute(new ThreadT1("任务"+i));
        }
        TimeUnit.SECONDS.sleep(1);
        executor.shutdown();
    }

}

D:\Java\jdk1.8.0_181\bin\java.exe "-javaagent:D:\JetBrains\IntelliJ IDEA 2019.3.2\lib\idea_rt.jar=50408:D:\JetBrains\IntelliJ IDEA 2019.3.2\bin" -Dfile.encoding=UTF-8 -classpath D:\Java\jdk1.8.0_181\jre\lib\charsets.jar;D:\Java\jdk1.8.0_181\jre\lib\deploy.jar;D:\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;D:\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;D:\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;D:\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;D:\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;D:\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;D:\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;D:\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;D:\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;D:\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;D:\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;D:\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;D:\Java\jdk1.8.0_181\jre\lib\javaws.jar;D:\Java\jdk1.8.0_181\jre\lib\jce.jar;D:\Java\jdk1.8.0_181\jre\lib\jfr.jar;D:\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;D:\Java\jdk1.8.0_181\jre\lib\jsse.jar;D:\Java\jdk1.8.0_181\jre\lib\management-agent.jar;D:\Java\jdk1.8.0_181\jre\lib\plugin.jar;D:\Java\jdk1.8.0_181\jre\lib\resources.jar;D:\Java\jdk1.8.0_181\jre\lib\rt.jar;C:\Users\63111\Desktop\springDemo\springBootDemo\target\classes;D:\repository\org\springframework\boot\spring-boot-starter-web\2.3.0.BUILD-SNAPSHOT\spring-boot-starter-web-2.3.0.BUILD-20200515.011136-707.jar;D:\repository\org\springframework\boot\spring-boot-starter\2.3.0.BUILD-SNAPSHOT\spring-boot-starter-2.3.0.BUILD-20200515.011136-707.jar;D:\repository\org\springframework\boot\spring-boot-starter-logging\2.3.0.BUILD-SNAPSHOT\spring-boot-starter-logging-2.3.0.BUILD-20200515.011136-707.jar;D:\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.2\log4j-to-slf4j-2.13.2.jar;D:\repository\org\apache\logging\log4j\log4j-api\2.13.2\log4j-api-2.13.2.jar;D:\repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;D:\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;D:\repository\org\springframework\boot\spring-boot-starter-json\2.3.0.BUILD-SNAPSHOT\spring-boot-starter-json-2.3.0.BUILD-20200515.011136-707.jar;D:\repository\com\fasterxml\jackson\core\jackson-databind\2.11.0\jackson-databind-2.11.0.jar;D:\repository\com\fasterxml\jackson\core\jackson-annotations\2.11.0\jackson-annotations-2.11.0.jar;D:\repository\com\fasterxml\jackson\core\jackson-core\2.11.0\jackson-core-2.11.0.jar;D:\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.0\jackson-datatype-jdk8-2.11.0.jar;D:\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.0\jackson-datatype-jsr310-2.11.0.jar;D:\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.0\jackson-module-parameter-names-2.11.0.jar;D:\repository\org\springframework\boot\spring-boot-starter-tomcat\2.3.0.BUILD-SNAPSHOT\spring-boot-starter-tomcat-2.3.0.BUILD-20200515.011136-707.jar;D:\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.35\tomcat-embed-core-9.0.35.jar;D:\repository\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;D:\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.35\tomcat-embed-websocket-9.0.35.jar;D:\repository\org\springframework\spring-web\5.2.6.RELEASE\spring-web-5.2.6.RELEASE.jar;D:\repository\org\springframework\spring-beans\5.2.6.RELEASE\spring-beans-5.2.6.RELEASE.jar;D:\repository\org\springframework\spring-webmvc\5.2.6.RELEASE\spring-webmvc-5.2.6.RELEASE.jar;D:\repository\org\springframework\spring-aop\5.2.6.RELEASE\spring-aop-5.2.6.RELEASE.jar;D:\repository\org\springframework\spring-context\5.2.6.RELEASE\spring-context-5.2.6.RELEASE.jar;D:\repository\org\springframework\spring-expression\5.2.6.RELEASE\spring-expression-5.2.6.RELEASE.jar;D:\repository\org\springframework\boot\spring-boot-devtools\2.3.0.BUILD-SNAPSHOT\spring-boot-devtools-2.3.0.BUILD-20200515.011136-707.jar;D:\repository\org\springframework\boot\spring-boot\2.3.0.BUILD-SNAPSHOT\spring-boot-2.3.0.BUILD-20200515.011136-707.jar;D:\repository\org\springframework\boot\spring-boot-autoconfigure\2.3.0.BUILD-SNAPSHOT\spring-boot-autoconfigure-2.3.0.BUILD-20200515.011136-707.jar;D:\repository\org\projectlombok\lombok\1.18.12\lombok-1.18.12.jar;D:\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;D:\repository\org\springframework\spring-core\5.2.6.RELEASE\spring-core-5.2.6.RELEASE.jar;D:\repository\org\springframework\spring-jcl\5.2.6.RELEASE\spring-jcl-5.2.6.RELEASE.jar com.example.demo.demo.threadPoolDemo.ThreadPoolDemo3
1591608247391,pool-1-thread-1,开始执行任务:ThreadT1{taskName='任务0'}
pool-1-thread-1正在处理任务0
1591608247392,pool-1-thread-3,开始执行任务:ThreadT1{taskName='任务2'}
pool-1-thread-3正在处理任务2
1591608247392,pool-1-thread-2,开始执行任务:ThreadT1{taskName='任务1'}
pool-1-thread-2正在处理任务1
1591608247392,pool-1-thread-3,任务:ThreadT1{taskName='任务2'},执行完毕!
1591608247392,pool-1-thread-7,开始执行任务:ThreadT1{taskName='任务6'}
pool-1-thread-7正在处理任务6
1591608247392,pool-1-thread-7,任务:ThreadT1{taskName='任务6'},执行完毕!
1591608247392,pool-1-thread-1,任务:ThreadT1{taskName='任务0'},执行完毕!
1591608247392,pool-1-thread-4,开始执行任务:ThreadT1{taskName='任务3'}
1591608247392,pool-1-thread-6,开始执行任务:ThreadT1{taskName='任务5'}
pool-1-thread-6正在处理任务5
1591608247392,pool-1-thread-5,开始执行任务:ThreadT1{taskName='任务4'}
pool-1-thread-5正在处理任务4
1591608247393,pool-1-thread-5,任务:ThreadT1{taskName='任务4'},执行完毕!
1591608247393,pool-1-thread-10,开始执行任务:ThreadT1{taskName='任务9'}
pool-1-thread-10正在处理任务9
1591608247393,pool-1-thread-10,任务:ThreadT1{taskName='任务9'},执行完毕!
1591608247392,pool-1-thread-2,任务:ThreadT1{taskName='任务1'},执行完毕!
1591608247393,pool-1-thread-9,开始执行任务:ThreadT1{taskName='任务8'}
pool-1-thread-9正在处理任务8
1591608247393,pool-1-thread-9,任务:ThreadT1{taskName='任务8'},执行完毕!
1591608247393,pool-1-thread-8,开始执行任务:ThreadT1{taskName='任务7'}
1591608247393,pool-1-thread-6,任务:ThreadT1{taskName='任务5'},执行完毕!
pool-1-thread-4正在处理任务3
1591608247393,pool-1-thread-4,任务:ThreadT1{taskName='任务3'},执行完毕!
pool-1-thread-8正在处理任务7
1591608247394,pool-1-thread-8,任务:ThreadT1{taskName='任务7'},执行完毕!
1591608248393,pool-1-thread-8,关闭线程池!

Process finished with exit code 0

从输出结果中可以看到,每个需要执行的任务打印了3行日志,执行前由线程池的beforeExecute打印,执行时会调用任务的run方法,任务执行完毕之后,会调用线程池的afterExecute方法,从每个任务的首尾2条日志中可以看到每个任务耗时2秒左右。线程池最终关闭之后调用了terminated方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值