线程池和使用

这篇具有很好参考价值的文章主要介绍了线程池和使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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. 无界队列可能会引起内存溢出。

因此,在某些情况下,我们可能需要自己实现线程池来满足特定需求。文章来源地址https://www.toymoban.com/news/detail-476857.html

到了这里,关于线程池和使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 密码如何“加盐加密”处理?程序员一定要掌握的知识

    目录 前言 一、手写加盐算法 1.1、加密 1.1.1、加密思路 1.1.2、加密简图 1.1.3、代码实现 1.2、解密 1.2.1、解密思路 1.2.2、解密代码 1.3、验证 二、使用 Spring Security 框架实现加盐算法 为什么要使用加盐的方式对密码进行加密?我们知道传统的 md5 加密方式是可以通过 “彩虹表”

    2024年02月16日
    浏览(36)
  • 作为C/C++程序员你可以不使用但你必须会的Linux调试器-gdb(GNU Debugger)

    gdb(GNU Debugger) 是一个用于调试 Linux 系统的软件工具。在学习 Linux 的过程中,gdb 的重要性不言而喻。以下是 gdb 在 Linux 学习者中的重要性的详细说明: 帮助理解 Linux 系统的运作方式:gdb 是一个强大的调试工具,可以帮助学习者深入了解 Linux 系统的运作方式。通过使用 gdb,学习

    2024年02月07日
    浏览(39)
  • 程序员都熟悉但不一定说得清的操作系统基本概念

    任何计算机系统都包含一个名为操作系统的基本程序集合。在这个集合里,最重要的程序称为内核(kernel)。当操作系统启动时,内核被装入到RAM中,内核中包含了系统运行所必不可少的很多核心过程(procedure)。其他程序是一些不太重要的使用程序,尽管这些程序为用户提

    2024年02月02日
    浏览(35)
  • 【如何确定自己作为程序员的职业发展方向?】

    优秀的程序员在选择自己的职业方向时,通常会考虑以下几个因素: 兴趣和热情:程序员应该选择对自己有兴趣并且热情的领域。兴趣可以保持你的工作动力,并且更容易取得成功。 技术发展潜力:选择一个技术发展潜力大的方向可以确保你的职业长期稳定发展。例如,人

    2024年02月09日
    浏览(36)
  • 作为程序员,你很有必要了解一下IVX

    iVX 是一个“零代码”的可视化编程平台,拥有方便的在线集成开发环境,不需要下载开发环境,打开浏览器即可随时随地进行项目编辑。iVX 还拥有“一站式”的云资源,通过这一套一站式服务,iVX 可以实现一站式研发、一站式部署、一站式维护。iVX相当于“一款零代码可视

    2024年02月15日
    浏览(42)
  • 【闪击Linux系列P9】程序员一定要了解的计算机管理理念——描述与组织

    ​ 前言 大家好吖,欢迎来到 YY 滴 Linux系列 ,热烈欢迎! 本章主要内容面向接触过Linux的老铁,从操作系统层面向大家介绍进程: 主要内容含: 欢迎订阅 YY 滴Linux专栏!更多干货持续更新!以下是传送门! 订阅专栏阅读: YY 的《Linux》系列 ❀❀❀❀❀ 【Linux】Linux环境搭建

    2024年02月12日
    浏览(34)
  • 猫头虎分享:AI时代SaaS项目程序员一定要懂的技术名词详解(下)

    博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接 : 🔗 精选专栏 : 《面试题大全》 — 面试准备的宝典! 《IDEA开发秘籍》 — 提升你的IDEA技能! 《100天精通鸿蒙》 — 从Web/安卓到鸿蒙大师! 《100天精通Golang(基础入门篇)》 — 踏入

    2024年02月21日
    浏览(35)
  • 作为一名程序员,如何写出一手让同事膜拜的漂亮代码?

    整洁的代码 有意义的命名 函数命名 变量命名 函数的定义 注释的规范 代码的长度 代码的对齐 我写代码已经有好几年了,最近看了一本书叫做《代码整洁之道》。我发现这本书中介绍的一些内容对我来说非常有启发性。书中提到的一些方法和技巧让我重新审视了自己的代码

    2024年02月02日
    浏览(38)
  • chatGPT4问世,作为一个程序员应当如何去理解?

    前几年 AI 发展也遇到过许多瓶颈,甚至很多AI投资者因为技术得不到突破而破产。但近几年AI技术飞速发展,特别是今天的主题chatGPT 第一次问世还只是一个帮学生写作业的工具,第二次迭代即可完成大部分市场业务,回答很多刁钻的问题。 有人测试过问chatGPT一些很难以回答

    2023年04月10日
    浏览(46)
  • 【作为程序员,你有什么让人眼前一亮的代码实现方式?】

    随着科技的不断发展,编程语言也在不断更新和改进。作为程序员,我们需要选取一种适合自己的高级编程语言来完成项目任务。下面将介绍常见的三种高级编程语言:Python、Java和C++。 Python Python是一种高级编程语言,具有简单易学、可读性强、效率高等特点。它广泛应用于

    2024年02月06日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包