线程池(一)-java内置线程池 ThreadPoolExecutor与自定义线程池

一、什么是线程池

线程池其实是一种多线程处理形式,处理过程中可以将任务添加到队列中,然后在创建线程后自动启动这些任务

二、线程池的作用

线程池可以根据系统的需求和硬件环境灵活地控制线程的数量,且可以对所有线程进行统一的管理和控制,从而提高系统的运行效率,降低系统运行压力

1、线程和任务分离,提升线程重用性
2、控制线程并发数量,降低服务器压力,统一管理所有线程
3、提升系统响应速度(例如创建线程的时间为T1,执行任务时间为T2,销毁线程时间为T3,那么使用线程池后就节省了T1和T3的时间)

三、ThreadPoolExecutor 类

构造方法

public ThreadPoolExecutor(
	int corePoolSize,					//核心线程数量:如果当前运行的线程数量没有达到 corePoolSize,则新建一个线程,否则加入到任务队列中
	int maximumPoolSize,				//最大线程数:当前系统最多存在的线程数
	long keepAliveTime,					//最大空闲时间:线程空闲的最大时间,超出时间该线程会销毁;设置allowCodeThreadTimeOut(true/false),可控制核心线程是否销毁,默认false 表示允许核心线程即使超过最大线程时间也不会销毁
	TimeUnit unit,						//时间单位:	线程空闲的最大时间的单位
	BlockingQueue<Runnable> workQueue,	//任务队列:	核心线程数量满了之后,提交的任务加入到队列中,等待核心线程数减少后再去创建线程;当任务队列已满,但没有达到最大线程数时,则新建非核心线程
	ThreadFactory threadFactory,		//线程工厂:	自定义线程的创建
	RejectedExecutionHandler handler	//饱和处理机制:当任务队列已满且达到最大线程数时,采取的措施
)	

四、线程池工作流程

1、流程图

在这里插入图片描述

2、场景描述

1、a客户(任务)去银行办理业务,但银行刚开始营业, 窗口服务员还未就位(相当于线程池中初始线程数量为0),于是经理(线程池管理者)就安排1号工作人员接待客户(创建线程并执行任务)

2、在a客户业务还没办理完时,b客户(任务)又来了,于是经理(线程池管理者)就安排2号工作人员接待b客户(创建新线程并执行任务)

3、假设该银行总共就2个窗口(核心线程数为2)

4、在a、b客户都没有结束的情况下c客户来了,于是经理(线程池管理者)就安排C客户先做到银行大厅的座位上(空位相当于任务队列)等候,当1或2号工作人员空闲后就可以去办理业务

5、假设银行只用1个等候座位(任务队列为1)

6、此时d客户又到了银行,工作人员都在忙,大厅座位也满了,于是经理(线程池管理者)赶紧安排临时工(新创建的线程)在大堂站着给d客户办理业务;

7、 加入前面的业务都没有结束的时候e客户来了,此时正式工作人员、临时工都在满,且座位也满了(正式工作人员加临时工就是最大线程数),于是经理(线程池管理者)只能按照《超出银行最大接待能力处理办法》(饱和处理机制)拒接e客户

8、最后进来办业务的人少了,大厅的临时工空闲时间也超过了1小时(最大空闲时间),经理(线程池管理者)就会让这部分空闲的员工下班(销毁线程);但为了办证银行正常工作(有一个allowCodeThreadTimeOut变量控制是否允许销毁核心线程,默认false),即使正式工闲着,也不提前下班,所有1、2号工作人员继续上班(线程池内保留核心线程;只有当allowCodeThreadTimeOut=true 时销毁核心线程)

五、自定义线程池

1、编写任务类

public class MyTask implements Runnable{
	
	//任务id
    private int id;

    public MyTask(int id){
        this.id=id;
    }

    @Override
    public void run() {
        String name=Thread.currentThread().getName();
        System.out.println("线程:"+name+"-->即将执行任务"+id);
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程:"+name+"执行完成"+id);
    }

    @Override
    public String toString() {
        return "MyTask{" +
                "id=" + id +
                '}';
    }
}

2、编写线程类,用于执行任务

public class MyThread extends  Thread{

    private List<Runnable> tasks;

    public MyThread(String name, List<Runnable> tasks){
        super(name);
        this.tasks=tasks;

    }

    @Override
    public void run() {
        while (tasks.size() > 0){
            Runnable r= tasks.remove(0);
            r.run();
        }
    }
}

3、编写线程池类,用于管理线程的执行

public class MyThreadPool {

    private List<Runnable>  tasks = Collections.synchronizedList(new LinkedList<>());
    /**
     * 当前线程数
     */
    private int num;
    /**
     * 核心线程数
     */
    private int corePoolSize;
    /**
     * 最大线程数
     */
    private int maxSize;
    /**
     * 任务队列数
     */
    private int workSize;

    public MyThreadPool(int corePoolSize, int maxSize, int workSize) {
        this.corePoolSize = corePoolSize;
        this.maxSize = maxSize;
        this.workSize = workSize;
    }
	/**
     * 提交任务
     */
    public void submit(Runnable r){

        if (tasks.size()>=workSize && tasks.size() > maxSize){
            System.out.println("任务:"+r+"被丢弃了");
        }else{
            tasks.add(r);
            execTask(r);
        }
    }

    public void execTask(Runnable r){
        if (corePoolSize > num){
            new MyThread("核心线程:"+num,tasks).start();
            num++;
        }else  if(num < maxSize){
            new MyThread("非核心线程:"+num,tasks).start();
            num++;
        }else{
            System.out.println("任务:"+r+"被缓存了");
        }
    }

}

4、测试

public class Demo {
    public static void main(String[] args) {
        MyThreadPool myThreadPool = new MyThreadPool(2, 4, 20);
        for (int i =0;i< 300;i++){
            MyTask myTask = new MyTask(i);
            myThreadPool.submit(myTask);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值