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,我们可以更好的了解线程池的执行流程。


目录
相关文章
|
1天前
|
安全 Java 调度
Java线程:深入理解与实战应用
Java线程:深入理解与实战应用
11 0
|
1天前
|
Java
Java中的并发编程:理解和应用线程池
【4月更文挑战第23天】在现代的Java应用程序中,性能和资源的有效利用已经成为了一个重要的考量因素。并发编程是提高应用程序性能的关键手段之一,而线程池则是实现高效并发的重要工具。本文将深入探讨Java中的线程池,包括其基本原理、优势、以及如何在实际开发中有效地使用线程池。我们将通过实例和代码片段,帮助读者理解线程池的概念,并学习如何在Java应用中合理地使用线程池。
|
5天前
|
安全 Java
深入理解 Java 多线程和并发工具类
【4月更文挑战第19天】本文探讨了Java多线程和并发工具类在实现高性能应用程序中的关键作用。通过继承`Thread`或实现`Runnable`创建线程,利用`Executors`管理线程池,以及使用`Semaphore`、`CountDownLatch`和`CyclicBarrier`进行线程同步。保证线程安全、实现线程协作和性能调优(如设置线程池大小、避免不必要同步)是重要环节。理解并恰当运用这些工具能提升程序效率和可靠性。
|
6天前
|
安全 Java
java多线程(一)(火车售票)
java多线程(一)(火车售票)
|
6天前
|
安全 Java 调度
Java并发编程:深入理解线程与锁
【4月更文挑战第18天】本文探讨了Java中的线程和锁机制,包括线程的创建(通过Thread类、Runnable接口或Callable/Future)及其生命周期。Java提供多种锁机制,如`synchronized`关键字、ReentrantLock和ReadWriteLock,以确保并发访问共享资源的安全。此外,文章还介绍了高级并发工具,如Semaphore(控制并发线程数)、CountDownLatch(线程间等待)和CyclicBarrier(同步多个线程)。掌握这些知识对于编写高效、正确的并发程序至关重要。
|
6天前
|
安全 Java 程序员
Java中的多线程并发编程实践
【4月更文挑战第18天】在现代软件开发中,为了提高程序性能和响应速度,经常需要利用多线程技术来实现并发执行。本文将深入探讨Java语言中的多线程机制,包括线程的创建、启动、同步以及线程池的使用等关键技术点。我们将通过具体代码实例,分析多线程编程的优势与挑战,并提出一系列优化策略来确保多线程环境下的程序稳定性和性能。
|
7天前
|
缓存 分布式计算 监控
Java并发编程:深入理解线程池
【4月更文挑战第17天】在Java并发编程中,线程池是一种非常重要的技术,它可以有效地管理和控制线程的执行,提高系统的性能和稳定性。本文将深入探讨Java线程池的工作原理,使用方法以及在实际开发中的应用场景,帮助读者更好地理解和使用Java线程池。
|
7天前
|
存储 安全 Java
Java中的容器,线程安全和线程不安全
Java中的容器,线程安全和线程不安全
15 1
|
7天前
|
Java 开发者
Java中多线程并发控制的实现与优化
【4月更文挑战第17天】 在现代软件开发中,多线程编程已成为提升应用性能和响应能力的关键手段。特别是在Java语言中,由于其平台无关性和强大的运行时环境,多线程技术的应用尤为广泛。本文将深入探讨Java多线程的并发控制机制,包括基本的同步方法、死锁问题以及高级并发工具如java.util.concurrent包的使用。通过分析多线程环境下的竞态条件、资源争夺和线程协调问题,我们提出了一系列实现和优化策略,旨在帮助开发者构建更加健壮、高效的多线程应用。
7 0
|
8天前
|
存储 缓存 监控
Java线程池
Java线程池
47 1

热门文章

最新文章