Java 线程池

x33g5p2x  于2021-12-12 转载在 Java  
字(2.4k)|赞(0)|评价(0)|浏览(570)

线程池概念

在String内部,为了进行一些优化,引入了一个"字符串常量池"

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

为什么使用线程池??

使用线程池最大的原因是可以根据系统的需求和硬件环境灵活的控制线程的数量,可以对所有线程进行统一的管理和控制,从而提高系统运行效率,避免了频繁创建 / 销毁线程的开销

线程池组成部分

需要管理两个内容:①要执行的任务②执行任务的线程们

1.先有一个类,表示工作线程
2.还需要一个类,用来表示具体的工作内容 (借助Runnable 接口)
3.还需要一个数据结构来组织若干个任务 (BlockingQueue)
4.还需要一个数据结构来组织若干个线程 (List)

线程池 核心操作

execute

把一个任务加到线程池中

public void execute(Runnable command) throws InterruptedException {
    // 使用 延时加载 的方式来创建线程
    // 当线程池中的线程数量少于阈值,则创建新线程执行该任务
    // 否则添加进队列,等待其他线程结束之前的任务再执行该任务
    if(pool.size() < MAX_WORKER_COUNT){
        // 创建新线程
        Worker worker = new Worker(queue);
        // 执行任务
        worker.start();
        // 将 worker 添加到 线程池中
        pool.add(worker);
    }
    queue.put(command);
}

shutdown

销毁线程池中的所有线程

调用每个线程的interrupt方法,使线程中断;调用 interrupt 后,每个线程并不是立即结束,而是可能等待一段时间,所以需要再使用 join 方法,来等待每个线程都执行结束

第一个循环触发异常,终止线程
第二个是等待每个线程结束

public void shutdown() throws InterruptedException {
    // 终止掉所有的线程
    for(Worker worker : pool){
        worker.interrupt();
    }
    // interrupt后,每个线程不是立刻结束
    // 需等待每个线程执行结束
    for (Worker worker : pool){
        worker.join();
    }
}

全部代码:

public class ThreadDemo27 {
    // 使用这个类描述 当前的工作线程
    static class Worker extends Thread{
        // 每个 worker 线程都需要从任务队列中取任务
        // 需要能够获取到任务队列中的实例
        private BlockingQueue<Runnable> queue = null;

        public Worker(BlockingQueue<Runnable> queue) {
            this.queue = queue;
        }

        @Override
        public void run(){
            // 此处 while被try 包裹: 只要线程收到异常,就会立刻结束 run 方法(结束线程)
            try {
                while (!Thread.currentThread().isInterrupted()){
                    Runnable command = queue.take();
                    command.run();
                }
            }
            catch (InterruptedException e){
                // 线程被结束
                System.out.println(Thread.currentThread().getName() + " 线程结束");
            }
        }
    }

    static class MyThreadPool{
        //线程池中最多可同时执行的线程数量
        private static final int MAX_WORKER_COUNT = 5; // 一个线程内部应该有多少个线程,应该根据实际情况来定

        // 阻塞队列: 用于组织若干个任务
        private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
        // List: 用于组织若干个工作线程
        private List<Worker> pool = new ArrayList<>();

        /* * 实现 execute 方法: */
        public void execute(Runnable command) throws InterruptedException {
            // 使用 延时加载 的方式来创建线程
            // 当线程池中的线程数量少于阈值,则创建新线程执行该任务,否则添加进队列,等待其他线程结束之前的任务再执行该任务
            if(pool.size() < MAX_WORKER_COUNT){
                // 创建新线程
                Worker worker = new Worker(queue);
                // 执行任务
                worker.start();
                // 将 worker 添加到 线程池中
                pool.add(worker);
            }
            queue.put(command);

        }

       /* * 实现 shutdown 方法: */
        public void shutdown() throws InterruptedException {
            // 终止掉所有的线程
            for(Worker worker : pool){
                worker.interrupt();
            }
            // interrupt后,每个线程不是立刻结束
            // 需等待每个线程执行结束
            for (Worker worker : pool){
                worker.join();
            }
        }
    }
}

线程池:本质上是一个生产者—消费者模型

生产者: 调用 execute 的代码就是生产者,生产者成产了任务 (Runnable 对象)
消费者: Woker 线程 就是消费者,消费了队列中的任务
交易场所: BlockingQueue

当最初创建线程池实例的时候,此时线程池中没有线程
MyThreadPool pool = new MyThreadPool();
继续调用 execute,就会触发创建线程操作
pool.execute(new Command(i));

相关文章