Java线程池原理

本文详细介绍了Java中线程池的使用场景、优点以及核心原理。线程池能够降低资源消耗,提高响应速度和可管理性。通过核心线程、等待队列、非核心线程和饱和策略来管理任务执行。文中还提供了一个简单的线程池实现示例,展示了如何创建和关闭线程池,并给出了测试用例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程池适用场景

Java中经常需要用到多线程来处理一些业务,我们非常不建议单纯使用继承Thread或者实现Runnable接口的方式来创建线程,那样势必有创建及销毁线程耗费资源、线程上下文切换问题。同时创建过多的线程也可能引发资源耗尽的风险,这个时候引入线程池比较合理,方便线程任务的管理。
线程池涉及到的几个核心类及接口包括:Executor、Executors、ExecutorService、ThreadPoolExecutor、FutureTask、Callable、Runnable等。

使用线程池的优点

  • 降低资源消耗。通过重复利用已创建的线程降低线程创建、销毁线程造成的消耗。
  • 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控。

线程池原理

线程提交到线程池的处理流程如下:
在这里插入图片描述

  • 核心线程:有新任务提交时,首先检查核心线程数,如果核心线程都在工作,而且数量也已经达到最大核心线程数,则不会继续新建核心线程,而会将任务放入等待队列。
  • 等待队列:也叫阻塞队列,用于存储当核心线程都在忙时,继续新增的任务,核心线程在执行完当前任务后,也会去等待队列拉取任务继续执行。
  • 非核心线程:当等待队列满了,如果当前线程数没有超过最大线程数,则会新建线程执行任务。
  • 饱和策略:当等待队列已满,线程数也达到最大线程数时,线程池会根据饱和策略来执行后续操作,默认的策略是抛弃要加入的任务。

所以线程池的执行流程可以理解为:

  1. 核心线程区先进入进程,正常执行。
  2. 如果核心线程区的可容纳线程数已满,则线程进入阻塞队列等待并遵循先进先出的原则,等待核心线程执行完当前任务后拉取队列中线程继续执行。
  3. 判断阻塞队列是否已满,如未满则继续将进程存储在队列中。
  4. 如阻塞队列已满,则线程进入普通线程区。
  5. 普通线程区如未满,则创建线程执行任务正常执行。
  6. 普通线程区如果已满,则按照饱和策略进行处理。

代码实现线程池

线程池类ThreadPool:

//线程池:管理线程对象的容器,使用队列来解决这个问题
//Queue ---- LinkedList 线程不安全
//需要将线程的任务添加到队列中,并且自动执行任务
//这些线程都是守护线程
//核心线程 --- 执行
//最大线程数量 --- 辅助线程
//都处于等待状态
//怎么关闭线程池 --- join

public class ThreadPool extends ThreadGroup{

    private boolean isClosed = false;      //线程池开关,是否需要关闭
    private LinkedList taskQueue;
    private static int threadPool_ID = 1;

    //线程池构造方法
    public ThreadPool(int poolSize) {
        //规定线程池的名称
        super(threadPool_ID + "");
        //设置为守护线程
        setDaemon(true);
        //创建队列
        taskQueue = new LinkedList<>();
        //执行线程任务
        for(int i = 0;i < poolSize;i++) {
            new TaskThread(i).start();
        }
    }

    //负责从工作队列中取出任务并执行的内部类
    private class TaskThread extends Thread {

        private int id;     //任务编号

        public TaskThread(int id) {
            super(ThreadPool.this,id + "");
            this.id = id;
        }

        @Override
        public void run() {
            //判断当前线程是否处于中断状态
            while(!isInterrupted()) {
                Runnable task = null;
                //通过id获取队列中线程对象
                task = getTask(id);
                if(task == null) {
                    return;
                }
                try{
                    task.run();
                }catch(Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //取任务
    private synchronized Runnable getTask(int id) {
        try {
            while (taskQueue.size() == 0) {
                //循环使用线程去等待任务
                if (isClosed) {
                    return null;
                }
                System.out.println("工作线程" + id + "等待任务");
                wait();
            }
        } catch (InterruptedException e) {
            System.out.println("等待任务出现错误" + e.getMessage());
        }
        System.out.println("工作线程" + id + "开始执行任务");
        return (Runnable) taskQueue.removeFirst();
    }

    //添加新任务并且执行
    public synchronized void executeTask(Runnable task) {
        if(isClosed) {
            throw new IllegalStateException();
        }
        if(task != null) {
            taskQueue.add(task);      //向队列中添加一个任务
            //唤醒
            notify();
        }
    }

    //关闭线程池
    public synchronized void closeThreadPool() {
        if(!isClosed) {     //判断标识
            //等待线程任务执行完毕
            waitTaskFinish();
            isClosed = true;
            taskQueue.clear();
            interrupt();

        }
    }

    public void waitTaskFinish() {
        synchronized (this) {
            isClosed = true;
            notifyAll();
        }
        //制作一个线程数组,长度和线程组中活动数量相同
        Thread[] threads = new Thread[activeCount()];
        int count = enumerate(threads);
        //循环等待线程结束
        for(int i = 0;i < count;i++) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

测试类ThreadToolTest:

public class ThreadPoolTest {

    private static Runnable createTask(final int taskID) {
        return new Runnable() {
            @Override
            public void run() {
                System.out.println("开始" + taskID);
                System.out.println("start task");
                System.out.println("结束" + taskID);
                System.out.println("----------");
            }
        };
    }

    public static void main(String[] args) {
        ThreadPool threadPool = new ThreadPool(3);
        try {
            Thread.sleep(600);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i = 0;i < 5;i++) {
            threadPool.executeTask(createTask(i));
        }
        threadPool.waitTaskFinish();
        threadPool.closeThreadPool();
    }
}

参考文章

https://www.jianshu.com/p/9a8c81066201

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值