JAVA线程池总结及自定义线程池

简介: JAVA线程池总结及自定义线程池

引言


在前几年小编写过一篇关于线程池的总结:《线程总结》,现在回过头来看,总结的 还是比较详细的,不过当时并没有在项目中有过真实刺激的 体验,最近项目中偶然遇到了一次任务丢失的问题,我追踪了一下 代码, 发现由于不正当采用java内置线程池导致的, 应该是当时配置线程池的参数没有仔细计算导致的,关于这个问题我们后面博文在介绍,今天我们在看我java 内置 线程池代码以后,我们先动手自己写一个线程池来实现任务的提交和执行。这样我们可以更好的理解线程池的执行流程。如果读者对于java内置的线程的核心参数和执行流程不是很了解,可以点击上面链接,阅读博文。


一、在编写代码之前,我们先介绍几个核心参数的配置依据。


1.1、核心线程数量corePoolSize


核心线程数的设计需要根据任务的处理时间和每秒产生的任务数量来确定,例如执行一个任务需要0.1秒,系统百分之八十的时间没秒都会产生100个任务,那么我们想要在1秒内处理完这100个任务,就需要10个线程,此时我们就可以设计核心线程数量为10,当时实际情况不可能这么平均,所以一般我们按照2080原则设计即可,即按照百分之80的情况设计核心线程数量,剩下的百分之20可以利用最大线程数量处理。


1.2、任务队列长度(workQueue)


任务队列长度一般设计为核心线程数/单个任务执行时间*2(任务最大等待时间/s)即可,例如上面场景中,核心线程数设计为10,单个任务执行时间为0.1,则队列长度可以设计为200


1.3、最大线程数(maximumPoolSize)


最大线程数的设计除了需要参照核心线程数的条件外,还需要参照系统每秒产生的最大任务数决定,例如,上述环境中,如果系统每秒最大产生的任务数量是1000个,那么最大线程数=(最大任务数-任务队列长度)* 单个任务执行时间;既最大线程数=(1000-200)* 0.1 =80;当然最大线程数和服务器的硬件配置也有很大关系


上面的 参数配置公式,都是参考作用,在实际环境中,需要根据实际服务器的配置自行调整


二、定义线程池


2.1、模拟任务类

package com.threadpoll;
/**
 * @author zhenghao
 * @description:
 * @date 2020/6/3010:07
 */
public class MyTask implements Runnable {
    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.2、自定义线程类

package com.threadpoll;
import java.util.ArrayList;
import java.util.List;
/**
 * @author zhenghao
 * @description:
 * @date 2020/6/3010:13
 */
public class MyWorker extends Thread {
    private String name;
    private List<Runnable> tasks = new ArrayList<>();
    public MyWorker(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();
        }
    }
}

2.3、自定义线程池类

package com.threadpoll;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
 * @author zhenghao
 * @description: 自定义线程池
 * @date 2020/6/3015:06
 */
public class MyThreadPool {
    /**
     * 任务集合 多个线程同时remove 
     */
    private List<Runnable> tasks = Collections.synchronizedList(new LinkedList<>());
    /**
     * 当前先测试数量
     */
    private int num;
    /**
     * 核心线程数量
     */
    private int coreThreadSize;
    /**
     * 最大线程数量
     */
    private int maxThreadSize;
    /**
     * 队列长度
     */
    private int workSize;
    public MyThreadPool( int coreThreadSize, int maxThreadSize, int workSize) {
        this.coreThreadSize = coreThreadSize;
        this.maxThreadSize = maxThreadSize;
        this.workSize = workSize;
    }
    /**
     * @Description: 提交队列
     * @author: zhenghao
     * @date: 2020/6/30 15:11
     */
    public void submitTask(Runnable r) {
        if (tasks.size() >= workSize) {
            System.out.println("任务" + r + "丢掉了");
        } else {
            //加入队列
            tasks.add(r);
            //执行队列
            execTask(r);
        }
    }
    private void execTask(Runnable r) {
        //判断是否需要创建核心线程池
        if (num < coreThreadSize) {
            //创建核心线程池执行
            new MyWorker("核心线程池" + num, tasks).start();
            num++;
        } else if (num < maxThreadSize) {
            //创建非核心线程池执行
            new MyWorker("非核心线程池" + num, tasks).start();
            num++;
        } else {
            System.out.println("任务" + r + "被缓存了");
        }
    }
}

2.4、测试类

package com.threadpoll;
/**
 * @author zhenghao
 * @description:
 * @date 2020/6/3010:07
 */
public class MyTask implements Runnable {
    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 +
                '}';
    }
}

大家通过调解任务数量,也就是测试类中的循环数量,可以看到不同的效果,大家可以测试一下, 然后通过这个小demo,我们可以更好的了解线程池的执行流程。


目录
相关文章
|
30天前
|
存储 Java 索引
用Java语言实现一个自定义的ArrayList类
自定义MyArrayList类模拟Java ArrayList核心功能,支持泛型、动态扩容(1.5倍)、增删改查及越界检查,底层用Object数组实现,适合学习动态数组原理。
80 4
|
1月前
|
设计模式 缓存 安全
【JUC】(6)带你了解共享模型之 享元和不可变 模型并初步带你了解并发工具 线程池Pool,文章内还有饥饿问题、设计模式之工作线程的解决于实现
JUC专栏第六篇,本文带你了解两个共享模型:享元和不可变 模型,并初步带你了解并发工具 线程池Pool,文章中还有解决饥饿问题、设计模式之工作线程的实现
125 3
|
1月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
121 1
|
1月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
137 1
|
2月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
124 0
|
2月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
193 16
|
3月前
|
缓存 并行计算 安全
关于Java多线程详解
本文深入讲解Java多线程编程,涵盖基础概念、线程创建与管理、同步机制、并发工具类、线程池、线程安全集合、实战案例及常见问题解决方案,助你掌握高性能并发编程技巧,应对多线程开发中的挑战。
|
3月前
|
Java 数据库 C++
Java异常处理机制:try-catch、throws与自定义异常
本文深入解析Java异常处理机制,涵盖异常分类、try-catch-finally使用、throw与throws区别、自定义异常及最佳实践,助你写出更健壮、清晰的代码,提升Java编程能力。
|
3月前
|
数据采集 存储 前端开发
Java爬虫性能优化:多线程抓取JSP动态数据实践
Java爬虫性能优化:多线程抓取JSP动态数据实践

热门文章

最新文章