线程池和使用

news2024/11/28 23:35:35

tip: 作为程序员一定学习编程之道,一定要对代码的编写有追求,不能实现就完事了。我们应该让自己写的代码更加优雅,即使这会费时费力。

推荐:体系化学习Java(Java面试专题)

文章目录

  • 线程池的目的
  • 线程池的参数
  • 几种封装的线程池

线程池的目的

线程池是一种用于管理和复用线程的机制。在多线程应用程序中,线程的创建和销毁需要消耗大量的系统资源,而线程池可以通过预先创建一定数量的线程,然后将任务分配给这些线程来避免频繁地创建和销毁线程,从而提高应用程序的性能和效率。线程池还可以控制并发线程的数量,避免过多的线程竞争资源导致的性能下降和系统崩溃。线程池是多线程编程中常用的一种技术,被广泛应用于各种类型的应用程序中。

线程池的参数

线程池的参数包括以下几个:

  1. 核心线程数(corePoolSize):线程池中最少保持的线程数。当有新任务提交时,如果当前线程池中的线程数小于核心线程数,则会创建新的线程来处理任务,即使有空闲的线程也会创建新的线程。

  2. 最大线程数(maximumPoolSize):线程池中最多能创建的线程数。当任务数量超过核心线程数时,线程池会创建新的线程来处理任务,但是最多只能创建最大线程数个线程。

  3. 空闲线程存活时间(keepAliveTime):当线程池中的线程数量超过核心线程数时,空闲线程的存活时间。如果线程在这段时间内没有处理任务,则会被销毁,直到线程池中的线程数量不超过核心线程数。

  4. 阻塞队列(workQueue):用于存放等待执行的任务的队列。当线程池中的线程数量已经达到核心线程数时,新的任务会被放入阻塞队列中等待执行。

  5. 线程工厂(threadFactory):用于创建新的线程。

  6. 时间单位(TimeUnit): 针对救急线程,unit 时间单位

  7. 拒绝策略(rejectedExecutionHandler):当线程池中的线程数量已经达到最大线程数,且阻塞队列已经满了时,新的任务将无法被处理。拒绝策略用于处理这种情况,可以选择抛出异常、直接丢弃任务、丢弃队列中最早的任务或者在调用线程中执行任务等方式。

这些参数可以根据具体应用程序的需求进行调整,以达到最佳的性能和效率。

package com.pany.camp.thread.pool;

import java.util.concurrent.*;

public class ThreadPoolExample {

    public static void main(String[] args) {
        // 创建一个线程池
        ExecutorService executor = new ThreadPoolExecutor(
                1,
                1,
                0L,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );

        // 提交10个任务给线程池
        for (int i = 1; i <= 10; i++) {
            final int taskId = i;
            executor.execute(new Runnable() {
                public void run() {
                    System.out.println("Task " + taskId + " is running in thread " + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Task " + taskId + " is completed");
                }
            });
        }

        // 关闭线程池
        executor.shutdown();
    }
}

在这里插入图片描述

几种封装的线程池

以下是几种常见的封装的线程池:

  1. FixedThreadPool:固定大小线程池,线程数量固定,不会自动调整线程数量。适用于负载比较稳定的情况。
package com.pany.camp.thread.pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FixedThreadPoolExample {

    public static void main(String[] args) {
        // 创建一个固定大小的线程池,大小为3
        ExecutorService executor = Executors.newFixedThreadPool(3);
        // 提交6个任务给线程池
        for (int i = 1; i <= 6; i++) {
            final int taskId = i;
            executor.execute(new Runnable() {
                public void run() {
                    System.out.println("Task " + taskId + " is running in thread " + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Task " + taskId + " is completed");
                }
            });
        }
        // 关闭线程池
        executor.shutdown();
    }
}

我们创建了一个固定大小为3的线程池,然后提交了6个任务给线程池。每个任务都会打印出自己的编号和当前运行的线程名,并且在执行完任务后打印出完成信息。由于线程池大小为3,因此只有3个任务会同时运行,其他任务需要等待空闲线程。最后,我们调用了 executor.shutdown() 方法来关闭线程池。

  1. CachedThreadPool:可缓存线程池,线程数量不固定,会根据任务数量自动调整线程数量。适用于负载比较不稳定的情况。
package com.pany.camp.thread.pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CachedThreadPoolExample {

    public static void main(String[] args) {
        // 创建一个可缓存的线程池
        ExecutorService executor = Executors.newCachedThreadPool();
        // 提交10个任务给线程池
        for (int i = 1; i <= 10; i++) {
            final int taskId = i;
            executor.execute(new Runnable() {
                public void run() {
                    System.out.println("Task " + taskId + " is running in thread " + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Task " + taskId + " is completed");
                }
            });
        }
        // 关闭线程池
        executor.shutdown();
    }
}

我们创建了一个可缓存的线程池,然后提交了10个任务给线程池。每个任务都会打印出自己的编号和当前运行的线程名,并且在执行完任务后打印出完成信息。由于线程池是可缓存的,因此会根据任务数量自动调整线程数量,如果有空闲线程可以使用,则会直接使用空闲线程,否则会创建新的线程。最后,我们调用了 executor.shutdown() 方法来关闭线程池。

  1. SingleThreadExecutor:单线程线程池,只有一个线程在工作,保证任务按照指定顺序执行。
package com.pany.camp.thread.pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SingleThreadExecutorExample {
    public static void main(String[] args) {
        // 创建一个单线程的线程池
        ExecutorService executor = Executors.newSingleThreadExecutor();
        // 提交5个任务给线程池
        for (int i = 1; i <= 5; i++) {
            final int taskId = i;
            executor.execute(new Runnable() {
                public void run() {
                    System.out.println("Task " + taskId + " is running in thread " + Thread.currentThread().getName());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Task " + taskId + " is completed");
                }
            });
        }
        // 关闭线程池
        executor.shutdown();
    }
}

我们创建了一个单线程的线程池,然后提交了5个任务给线程池。每个任务都会打印出自己的编号和当前运行的线程名,并且在执行完任务后打印出完成信息。由于线程池只有一个线程,因此所有任务都会按照顺序依次执行。最后,我们调用了 executor.shutdown() 方法来关闭线程池。

  1. ScheduledThreadPool:定时任务线程池,适用于需要定时执行任务的场景。
package com.pany.camp.thread.pool;

import cn.hutool.core.thread.ThreadUtil;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolExample {
    public static void main(String[] args) {
        // 创建一个大小为3的定时线程池
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
        // 延迟1秒后执行任务
        executor.schedule(() -> System.out.println("Task 1 is running in thread " + Thread.currentThread().getName()), 1, TimeUnit.SECONDS);
        // 延迟2秒后执行任务,之后每3秒执行一次
        executor.scheduleAtFixedRate(() -> System.out.println("Task 2 is running in thread " + Thread.currentThread().getName()), 2, 3, TimeUnit.SECONDS);
        // 延迟3秒后执行任务,之后每5秒执行一次
        executor.scheduleWithFixedDelay(() -> System.out.println("Task 3 is running in thread " + Thread.currentThread().getName()), 3, 5, TimeUnit.SECONDS);
        // 关闭线程池
        ThreadUtil.sleep(10000);
        executor.shutdown();
    }
}

我们创建了一个大小为3的定时线程池,然后提交了3个任务给线程池。第一个任务会延迟1秒后执行,第二个任务会延迟2秒后执行,并且之后每3秒执行一次,第三个任务会延迟3秒后执行,并且之后每5秒执行一次。每个任务都会打印出自己的编号和当前运行的线程名。最后,我们调用了 executor.shutdown() 方法来关闭线程池。

  1. WorkStealingPool:工作窃取线程池,线程数量固定,但是线程之间可以窃取任务执行,提高了任务执行的效率。
package com.pany.camp.thread.pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

public class WorkStealingPoolExample {
    public static void main(String[] args) throws InterruptedException {
        // 获取当前系统可用的处理器数量
        int processors = Runtime.getRuntime().availableProcessors();
        // 创建一个工作窃取线程池
        ExecutorService executor = Executors.newWorkStealingPool(processors);
        // 提交10个任务给线程池
        IntStream.range(1, 11).forEach(i -> executor.submit(() -> {
            System.out.println("Task " + i + " is running in thread " + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Task " + i + " is completed");
        }));
        // 等待所有任务完成
        executor.awaitTermination(5, TimeUnit.SECONDS);
        // 关闭线程池
        executor.shutdown();
    }
}

,我们使用 Runtime.getRuntime().availableProcessors() 获取当前系统可用的处理器数量,然后创建了一个工作窃取线程池。我们提交了10个任务给线程池,每个任务都会打印出自己的编号和当前运行的线程名,并且在执行完任务后打印出完成信息。由于工作窃取线程池的特性,线程会自动从其他线程窃取任务来执行,因此我们无法预测每个任务会在哪个线程中执行。最后,我们调用了 executor.awaitTermination(5, TimeUnit.SECONDS) 等待所有任务完成,然后调用了 executor.shutdown() 方法来关闭线程池。

这些线程池都是Java中自带的线程池,可以直接使用。不同的线程池适用于不同的场景,根据实际需要选择合适的线程池可以提高应用程序的性能和效率。

封装的线程池的缺点主要有以下几点:

  1. 无法满足特定需求:封装的线程池通常是为了方便使用而设计的,因此可能无法满足某些特定需求。例如,如果需要使用某种特定的线程调度算法,就需要自己实现线程池。

  2. 难以调试:封装的线程池通常会隐藏一些底层细节,这使得在出现问题时难以进行调试。例如,如果线程池中的某个任务出现了异常,我们可能无法知道是哪个任务出了问题。

  3. 可能存在性能问题:封装的线程池通常会提供一些默认配置,这可能无法满足某些高性能的需求。例如,如果需要使用更高效的队列实现,就需要自己实现线程池。

  4. 无界队列可能会引起内存溢出。

因此,在某些情况下,我们可能需要自己实现线程池来满足特定需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/626514.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

360,可真小看你了:耍流氓耍到日本人身上,凌晨2点笑得我胃疼

天下苦流氓软件久矣 大厂的软件&#xff0c;都有点牛皮癣特性&#xff1a;捆绑安装广告推广&#xff0c;简直无所不用其极&#xff0c;身为用户着实无可奈何。 此处点名四大全家桶家族——360、鲁大师、金山毒霸、2345。 说来好笑&#xff0c;之前发的文章不是有关于金山的嘛…

Cefsharp-Winform-113.3.50(chromium5672)最新版体验兼容性测试

一、下载nupkg包(4个)提示:(不支持H264,支持MP3,WEBGL,WEBGL2等)支持H264最新版本109.*自行搜索 winform包地址(依赖包下载地址如下):NuGet Gallery | CefSharp.WinForms 113.3.50 https://globalcdn.nuget.org/packages/cefsharp.winforms.113.3.50.nupkg https://…

仓库拣货标签10代—电子料架

CK_Label_v10 无线电子标签拣货系统特点与效益 无线通信&#xff0c;极简快速部署 超低功耗&#xff0c;墨水屏显示 多彩指示灯&#xff0c;支持24V外接供电 按键及三色高亮LED指示灯指示 3位0.8寸高亮LED数码管显示 提升作业速度与品质 实现无纸化标准化作业 缩短操…

怎么快速掌握Python爬虫技术?

Python总的来说是一门比较容易入门的编程语言&#xff0c;因为它的语法简洁易懂&#xff0c;而且有很多优秀的教程和资源可供学习。相比其他编程语言&#xff0c;Python 的学习曲线较为平缓&#xff0c;初学者可以很快上手&#xff0c;但要想深入掌握 Python&#xff0c;还需要…

chatgpt赋能python:用Python实现ping命令:掌握网络连接的艺术

用Python实现ping命令&#xff1a;掌握网络连接的艺术 当我们需要测试网络连接的时候&#xff0c;ping命令是最经典的选择之一。然而&#xff0c;在一些情况下&#xff0c;使用命令行并不是很方便。那么&#xff0c;有没有可能用Python编写一个类似ping的功能呢&#xff1f; …

ISO21434 概念阶段网络安全(六)

目录 一、概述 二、目标 三、项目定义 3.1 输入 3.1.1 先决条件 3.1.2 进一步支持信息 3.2 要求和建议 3.3 输出 四、网络安全目标 4.1 输入 4.1.1 先决条件 4.1.2 进一步支持信息 4.2 要求和建议 4.3 输出 五、网络安全概念 5.1 输入 5.1.1 先决条件 5.1.2 …

phpMyAdmin连接MySQL,出现服务器拒绝连接解决方法

当你登录mysql的时候出现下面情况时 把config.inc.php删除就可以&#xff0c;或者修改config.inc.php里的 $cfg[Servers][$i][controluser] ; $cfg[Servers][$i][controlpass] ; 注释掉就会弹出来要求登陆。 例如我的文件位置是在C:\wamp\apps\phpmyadmin4.1.14&#xff…

dreamer-cms docker复现

dreamer-cms docker复现 前言一&#xff0c;赛题复现二&#xff0c;人生第一个jar包1 ubuntu本地复现&#xff08;1&#xff09;创建文件夹&#xff08;2&#xff09;解压资源&#xff08;3&#xff09;安装并导入数据库&#xff08;4&#xff09;使用idea自动化部署&#xff0…

软件锁步冗余执行等安全机制是什么?

软件锁步冗余执行等安全机制是一种用于提高软件系统的功能安全性和可靠性的技术。它的基本思想是让两个或多个软件副本执行相同的功能&#xff0c;然后比较它们的输出&#xff0c;以检测和处理可能的故障。不同的安全机制有不同的特点和优缺点&#xff0c;例如&#xff1a; 锁…

Pull Request完整过程【记一次给antvis:G6的PR】

文章目录 前言Bug 重现问题排查解决方案old versionnew version收到回复 PR提交完整过程fork仓库 & clone代码仓添加upstreamfetch 新分支创建新分支完成修改&#xff08;注意commit规范&#xff09;push到个人仓库创建Pull Request填写PR信息 前言 G6正在进行v4到v5的版本…

基于多能互补的热电联供型微网优化运行(matlab代码)

目录 1 主要内容 多能互补模型 算例分析 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序基本复现《基于多能互补的热电联供型微网优化运行》&#xff0c;在需求侧对负荷类型进行分类&#xff0c;利用电负荷的弹性和系统供热方式的多样性&#xff0c;构建含电负荷时…

淘宝618每日一猜答案(6月9日)淘宝大赢家今日答案

淘宝6月9日每日一猜答案是什么&#xff1f;&#xff0c;接下来也会给大家来介绍一下6月9日淘宝大赢家每日一猜的答案。 淘宝每日一猜6月9日答案分享 活动问题&#xff1a;环球影城大酒店有几种主题房&#xff1f; 活动答案&#xff1a;【2种】 注意阿拉伯数字&#xff01; …

[游戏开发][Unity]Assetbundle加载篇(1)热更前准备与下载AB包清单

热更流程都不是固定的&#xff0c;每个人写的状态机也有所差别&#xff0c;但是一些必要步骤肯定不可能少&#xff0c;例如下载清单&#xff0c;对比版本&#xff0c;下载AB包&#xff0c;标记下载完成。 检查沙盒路径是否存在 public static string MakePersistentLoadPath(st…

UnityVR--组件7--动画事件BlendTree

目录 应用1&#xff1a;使用BlendTree实现站立和移动 应用2&#xff1a;人物跳跃事件&播放跳跃动画 应用3&#xff1a;开火动画事件&动画片段中建立事件监听 上一篇&#xff08;组件5--Animation动画&#xff09;已经做了2个动画片段&#xff0c;HeroIdle和HeroJump…

【C语言】qsort详细将解

系列文章目录 qsort目录 系列文章目录一、前言二、qosort是什么&#xff1f;二、qsort的使用1、原型2、参数3、头文件&#xff08;1&#xff09;qsort参数中的函数指针讲解 三、使用示例和运行截图1、整形例子&#xff08;升序&#xff09;3、字符例子&#xff08;降序&#xf…

Android——使用Service服务实现通信

实验目的&#xff1a; &#xff08;1&#xff09;能创建、启动和关闭服务 &#xff08;2&#xff09;能实现服务的通信 实验内容及原理&#xff1a; 设计一个服务的具体应用&#xff0c;实现服务的通信 实验设备及实验步骤&#xff1a; 实验设备&#xff1a;WindowsAndro…

VPS 和GPS 、SLAM 之间的爱恨情仇

注&#xff1a;该文章首发3D视觉工坊&#xff0c;链接如下3D视觉工坊 VPS 、GPS 、SLAM 的区别与联系 首先简单的阐述一下三者的定义&#xff1a; VPS全称为Visual Positioning System&#xff0c;即视觉定位系统。手机端(移动时代&#xff09;的VPS首次出现时间节点为2019年&…

Linux 负载均衡集群 LVS_NAT模式 LVS_DR模式

集群 由多台主机组成&#xff0c;只做一件事&#xff0c;对外表现为一个整体。 只干一件事 &#xff1a;集群 干不同的事&#xff1a;分布式 企业集群分类 负载均衡群集&#xff08;load balance cluster&#xff09; 提高系统响应效率&#xff0c;处理更多的访问请…

Qt6 C++基础入门3 对话框与MainWindow

目录 对话框MainWindow菜单工具栏 对话框 目前的对话框主要有以下几大类 文件对话框( QFile Dialog)消息对话框( QMessageBox)输入对话框( QInputDialog)颜色对话框( QColorDialog)字体对话框( QFontDialog) 这是七大对话框及其基本用法的实例参考&#xff0c;所有代码都写在…

《星岛日报》专访:欧科云链AML,助力数字资产合规及风险防控

6月1日&#xff0c;香港《适用于虚拟资产交易平台营运者的指引》及《打击洗钱指引》正式施行&#xff0c;香港虚拟资产发牌制度正式生效。作为深耕香港市场多年的Web3科技企业&#xff0c;欧科云链OKLink也正式推出的Onchain AML反洗钱合规解决方案&#xff0c;利用多年积累的海…