java实现手写一个简单版的线程池

下面是Java实现手写一个简单版的线程池的完整攻略。

什么是线程池?

线程池是管理线程的一种机制,它可以为任务分配线程、重复利用已创建的线程、控制并发线程数量,从而提高程序的性能和稳定性。

线程池的原理

线程池由一个线程池管理器(ThreadPoolExecutor)和若干个工作线程(Thread)组成。线程池管理器负责线程池的初始化、关闭、提交任务、监控线程池和任务队列等操作。工作线程则负责执行提交的任务。

如何手动实现线程池?

首先,我们需要自定义一个线程池类,该类需要继承 ThreadPoolExecutor 并重写构造器方法,定义线程池的基本参数(核心线程数、最大线程数、空闲线程存活时间、任务队列等),具体详见示例代码:

public class MyThreadPool extends ThreadPoolExecutor {
    public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    // 执行任务方法
    @Override
    public void execute(Runnable command) {
        super.execute(command);
    }

    // 关闭线程池方法
    @Override
    public void shutdown() {
        super.shutdown();
    }

    // 提交任务方法
    @Override
    public Future<?> submit(Runnable task) {
        return super.submit(task);
    }
}

接着,我们需要编写一个测试类,在测试类中构造自定义的线程池,提交任务,并测试线程池的基本功能,例如:执行任务、关闭线程池等,具体详见示例代码:

public class TestThreadPool {
    public static void main(String[] args) {
        MyThreadPool myThreadPool = new MyThreadPool(5, 10, 200, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), Executors.defaultThreadFactory());

        for (int i = 0; i < 20; i++) {
            myThreadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + ": 工作中...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        myThreadPool.shutdown();
    }
}

运行测试类后,我们可以看到线程池在执行任务的过程中,从池中获取线程执行任务,如果线程池中当前可用线程小于核心线程数,则创建新线程执行任务,如果线程池已经达到最大线程数,则将任务添加到工作队列中,等待空闲线程执行,当工作队列满了以后,将新任务拒绝执行。当线程池关闭时,会等待所有任务执行完毕,然后关闭线程池。

案例说明

示例一:启动10个线程执行20个任务

我们构造线程池时,核心线程数为5,最大线程数为10,线程空闲时间为200ms,任务队列为一个无限大的阻塞队列。在测试类中提交20个任务给线程池,从运行结果中可以看到线程池中最多只有10个线程在执行任务,当这10个线程都被占用时,新的任务需要等待空闲线程,等待时间为200ms,如果200ms后仍然没有空闲线程,则将任务添加到工作队列中,等待空闲线程执行。

public class TestThreadPool {
    public static void main(String[] args) {
        MyThreadPool myThreadPool = new MyThreadPool(5, 10, 200, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), Executors.defaultThreadFactory());

        for (int i = 0; i < 20; i++) {
            myThreadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + ": 工作中...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        myThreadPool.shutdown();
    }
}

示例二:使用自定义线程池和自定义任务

我们可以自定义线程池和线程池中执行的任务,在测试类中提交自定义任务给自定义线程池执行。

public class MyTask implements Runnable {
    private int taskNum;

    public MyTask(int num) {
        this.taskNum = num;
    }

    @Override
    public void run() {

        System.out.println("正在执行 task "+taskNum);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task "+taskNum+"执行完毕");
    }
}

public class MyThreadPool extends ThreadPoolExecutor {
    public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    // 执行任务方法
    @Override
    public void execute(Runnable command) {
        super.execute(command);
    }

    // 关闭线程池方法
    @Override
    public void shutdown() {
        super.shutdown();
    }

    // 提交任务方法
    @Override
    public Future<?> submit(Runnable task) {
        return super.submit(task);
    }
}

public class TestThreadPool {
    public static void main(String[] args) {
        MyThreadPool myThreadPool = new MyThreadPool(2, 3, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory());

        for (int i = 0; i < 10; i++) {
            myThreadPool.execute(new MyTask(i));
        }

        myThreadPool.shutdown();
    }
}

在上述代码中,我们定义了一个 MyTask 类,实现了 Runnable 接口,并重写了 run 方法。在 MyThreadPool 类中,我们使用了一个 ArrayBlockingQueue 作为任务队列,并重写了线程池类的基本方法。在测试类中,提交了10个自定义任务给自定义线程池执行,我们可以从结果中看到,线程池执行了10个任务。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java实现手写一个简单版的线程池 - Python技术站

(0)
上一篇 2023年5月18日
下一篇 2023年5月18日

相关文章

  • java模拟hibernate一级缓存示例分享

    让我为您简单讲解一下如何使用Java模拟Hibernate一级缓存。 一、什么是Hibernate一级缓存 Hibernate是一个Java持久层框架,其缓存机制为应用程序和数据库之间搭建了一个缓冲层,用于提高性能并优化数据库资源的使用。Hibernate一级缓存,也称为session缓存,是Hibernate提供的默认缓存机制。当运行应用程序时,Hiber…

    Java 2023年5月20日
    00
  • ehcache开源缓存框架_动力节点Java学院整理

    EhCache开源缓存框架攻略 什么是EhCache EhCache是一个流行的、开源的缓存框架,它提供了快速、高效、可靠的缓存服务。EhCache的主要特点如下: 支持内存缓存和磁盘缓存 支持LRU、LFU、FIFO等多种缓存清理策略 支持缓存数据的过期时间设置 支持集群下多个应用共享缓存 EhCache使用指南 本节将以Java Spring框架为例,讲…

    Java 2023年5月20日
    00
  • Java基础精讲方法的使用

    当我们学习Java基础时,方法是一个非常重要和基础的概念,掌握了方法的使用可以帮助我们更好地编写代码。下面是“Java基础精讲方法的使用”的完整攻略: 方法的定义与使用 在Java的编程中,方法是一组执行特定任务的语句块。方法定义和调用的语法如下: // 方法的定义 public static returnType methodName(parameter …

    Java 2023年5月23日
    00
  • 如何使用Reactor完成类似Flink的操作

    使用Reactor完成类似Flink的操作可以分为以下几个步骤: 创建Flux或Mono:首先需要创建Flux或Mono,Flux表示可以产生多个数据流,Mono表示只能产生一个数据流; 转换Flux或Mono:可以使用map()、flatMap()、filter()等函数对Flux或Mono进行转换,获得想要的结果; 订阅Flux或Mono:最后需要订阅F…

    Java 2023年5月20日
    00
  • 深入浅出Java中重试机制的多种方式

    深入浅出Java中重试机制的多种方式 在开发中,有时会需要对某些操作进行多次尝试,以增加操作的稳定性和可靠性。这时,使用重试机制可以很好地解决这一问题。本文将详细介绍Java中重试机制的多种实现方式。 1. 基于while循环的重试机制 最简单的重试机制就是在while循环中执行某个操作,并在某些限定条件下进行多次尝试。例如以下示例代码: int count…

    Java 2023年5月27日
    00
  • mybatis-plus中BaseMapper入门使用

    下面我详细讲解一下“mybatis-plus中BaseMapper入门使用”的完整攻略。 什么是mybatis-plus mybatis-plus是mybatis的增强工具,它可以让我们更方便、更快捷地开发mybatis项目。其中最为常用的模块就是BaseMapper,它提供了单表CRUD的基本SQL,减少了我们重复写SQL的工作量。 BaseMapper的…

    Java 2023年5月20日
    00
  • java日期时间格式化@JsonFormat与@DateTimeFormat的使用

    下面就为您详细讲解“java日期时间格式化@JsonFormat与@DateTimeFormat的使用”的完整攻略。 一、前言 在开发 Java 项目时,常常需要对日期时间进行格式化。这时,我们就可以使用@JsonFormat和@DateTimeFormat这两个注解来实现。 二、@JsonFormat注解 @JsonFormat注解是用来指定Java对象的…

    Java 2023年5月20日
    00
  • java中的常见关键字解析

    Java中的关键字是具有特殊含义的词汇,它们在编写Java程序时起着非常重要的作用。在本文中,我们将详细讲解Java中的常见关键字及其用法。 标识符 Java中的标识符是用来命名变量、方法和类等的名称,标识符需要满足以下要求: 标识符是由字母、数字、下划线组成的序列。 第一个字符必须是字母或下划线。 标识符不能是Java关键字。 标识符区分大小写。 示例: …

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部