返回顶部
首页 > 资讯 > 后端开发 > Python >Java线程池由浅入深掌握到精通
  • 965
分享到

Java线程池由浅入深掌握到精通

2024-04-02 19:04:59 965人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录1.为什么使用线程池?2.线程池的好处:3.线程池使用的场合4.创建和停止线程5.停止线程池的方法6.暂停和恢复线程池1.为什么使用线程池? 反复创建线程开销大,可以复用线程池

1.为什么使用线程池?

反复创建线程开销大,可以复用线程池
过多的线程会占用太多的内存

解决以上问题的方法:

  • 用少量的线程,避免内存占用过多
  • 让这部分线程都保持工作,且反复执行任务,避免生命周期的损耗

2.线程池的好处:

加快响应速度,提高用户体验
合理利用CPU内存
统一管理

3.线程池使用的场合

服务器接受大量请求时,使用线程池技术是非常合适的,它可以大大减少线程的创建和销毁次数,提高服务器的工作效率。在实际开发中,如果创建5个以上 的线程,那么就可以使用线程池来管理线程。

4.创建和停止线程

线程池构造方法的参数?
线程池应该手动创建和自动创建那个更好?
线程池里的线程数量设置未多少合适?
停止线程的正确方法?

线程池构造函数的参数:

线程池构造函数的参数

corePoolSize: 核心线程数
线程池在完成初始化后,默认情况下,线程池中并没有任何线程,会等到有任务到来时再去创建新的线程去执行任务。
maxPoolSize:在核心线程的基础上,额外增加的线程数的上限。

在这里插入图片描述

根据图可知添加线程的规则:

1.如果线程数小于corePoolSize,即使其他工作线程处于空闲状态,也会创建一个新线程来运行任务。
2.如果线程数等于或大于corePoolSize但少于maximumPoolSize,则将任务放入队列。
3.如果线程池已满,并且线程数小于maxPoolSize,则创建一个新线程来运行任务。
4.如果队列已满,并且线程数大于或等于maxPoolSzie,则参数拒绝该任务。

添加线程规则

添加线程判断顺序:corePoolSize——workQueue——maxPoolSize

比如线程池的核心线程是5个,最大线程池大小为10个,队列为50个。
则线程池的请求最多会创建5个,然后任务将被添加到队列中,直到达到50。队列已满时,将创建最新的线程maxPoolSize,最多达到10个,如果再来任务就直接拒绝。

keepAliveTime:如果线程池当前的线程数多于corePoolSize,那么如果多余的线程空闲时间超过keepAliveTime,那么就会终止。

ThreadFactory:
默认使用Executors.defaultThreadFactory()
创建出来的线程都在同一个线程组。
如果自己指定ThreadFactory,那么就可以改变线程名、线程组、优先级、是否是守护线程等等。

常见的3中队列类型:
直接交接:SynchronousQueue
无界队列:LinkedBlockingQueue
有界队列:ArrayBlockingQueue

线程池应该手动创建和自动创建那个更好?

手动创建好,因为这样可以明确线程池的运行规则和避开资源浪费的风险。

  • newFixedThreadPool:容易造成大量内存占用,可能导致DOM
    
    public class FixedThreadPoolTest  {
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newFixedThreadPool(4);
            for (int i = 0; i < 500; i++) {
                executorService.execute(new Task());
            }
        }
    }
    class Task implements Runnable{
    
        @Override
        public void run() {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
        }
    }
    
  • newSingleThreadExecutor:当请求堆积的时候,可能会占用大量内存。
    
    //演示FixedThreadPool出错
    public class FixedThreadPoolOOM {
        private static ExecutorService executorService = Executors.newFixedThreadPool(1);
    
        public static void main(String[] args) {
            for (int i = 0; i < Integer.MAX_VALUE; i++) {
                executorService.execute(new SubThread());
            }
        }
    }
    class SubThread implements Runnable{
    
        @Override
        public void run() {
            try {
                Thread.sleep(10000000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
  • newCachedThreadPool:弊端在于第二个参数maximumPoolSize被设置为了Integer.MAX_VALUE,这可能会创建数量非常多的线程,甚至导致DOM
  • newScheduledThreadPool:原因和newCachedThreadPool一样

常见的线程池:

FixedThreadPool

在这里插入图片描述

CachedThreadPool:可缓存线程池,具有自动回收多余线程的功能

在这里插入图片描述

ScheduledThreadPool:支持定时及周期性任务执行的线程池
SingleThreadExecutor:单线程的线程池只会用唯一的工作线程来执行任务
原理和FixedThreadPool一样,但是线程数量被设为1

四种线程池的构造方法的参数:

在这里插入图片描述

阻塞队列分析:

在这里插入图片描述

5.停止线程池的方法

  • shutdown:只是将线程池的状态设置为 shutdown 状态,但任务并没有中断,还是会继续执行下去。此时线程池不会接受新的任务,只是将原有的任务执行结束。
  • shutdownNow:将线程池的状态设置为STOP,正在执行的任务会停止,没被执行的任务会被返回。
  • isshutdown:当调用shutdown()或shutdownNow()方法后返回为true,否则返回为false。
  • isTerminated:线程任务全部执行完返回true
  • awaitTerminated:有两个参数,第一个是long类型的数值,第二个是时间类型TimeUnit,用于设置阻塞时间。它是一个阻塞的方法,若线程池一直运行则会一直阻塞,直到线程池关闭返回true,或阻塞时间超过你设置的这个时间,则返回false。此方法必须放在shutdown()方法之后,否则一直在阻塞,或超过设置的阻塞时间返回false。

//演示关闭线程池
public class ShutDown {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 500; i++) {
            executorService.execute(new ShutDownTask());
        }
        Thread.sleep(1500);
//        executorService.shutdown();
//        System.out.println(executorService.isShutdown());
        executorService.awaitTermination(3L, TimeUnit.SECONDS);
    }
}
class ShutDownTask implements Runnable{

    @Override
    public void run() {
        try {
            Thread.sleep(500);
            System.out.println(Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

6.暂停和恢复线程池


//暂停线程池
 pauseAbleThreadPool.pause();
 //恢复线程池
 pauseAbleThreadPool.resume();

代码实现:


//演示每个任务执行前后放钩子函数
public class PauseAbleThreadPool extends ThreadPoolExecutor {
    private final ReentrantLock lock = new ReentrantLock();
    private Condition unpaused = lock.newCondition();
    private boolean isPaused;

    public PauseAbleThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

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

    public PauseAbleThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    public PauseAbleThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        lock.lock();
        try {
            while (isPaused) {
                unpaused.await();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    private void pause() {
        lock.lock();
        try {
            isPaused = true;
        } finally {
            lock.unlock();
        }
    }

    public void resume() {
        lock.lock();
        try {
            isPaused = false;
            unpaused.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        PauseAbleThreadPool pauseAbleThreadPool = new PauseAbleThreadPool(10, 20, 10l, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("我被执行");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        for (int i = 0; i < 10000; i++) {
            pauseAbleThreadPool.execute(runnable);
        }
        Thread.sleep(1500);
        pauseAbleThreadPool.pause();
        System.out.println("线程池被暂停了");
        Thread.sleep(1500);
        pauseAbleThreadPool.resume();
        System.out.println("线程池被恢复了");

    }
}

实现原理及源码分析
线程池的组成部分:

  • 线程池管理器
  • 工作线程
  • 任务队列
  • 任务接口(Task)

在这里插入图片描述

到此这篇关于Java线程池由浅入深掌握到精通的文章就介绍到这了,更多相关Java 线程池内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java线程池由浅入深掌握到精通

本文链接: https://lsjlt.com/news/137282.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java线程池由浅入深掌握到精通
    目录1.为什么使用线程池?2.线程池的好处:3.线程池使用的场合4.创建和停止线程5.停止线程池的方法6.暂停和恢复线程池1.为什么使用线程池? 反复创建线程开销大,可以复用线程池 ...
    99+
    2024-04-02
  • Java 线程池详解:从入门到精通
    Java 线程池是一种用于管理和复用线程的资源池。它提供了创建、销毁和管理线程的统一机制,帮助开发者提升应用程序性能并简化并发编程。 优点 提高性能:线程池可以节省创建和销毁线程的开销,尤其是在需要频繁创建和销毁线程的应用程序中。 控制...
    99+
    2024-03-13
    线程池
  • Java由浅入深带你精通继承super
    目录什么是继承背景super关键字protected 关键字final 关键字什么是继承 面向对象的特征: 封装:不必要公开的数据成员和方法,使用private关键字进行修饰。意义:...
    99+
    2024-04-02
  • Java由浅入深带你掌握图的遍历
    目录1.图的遍历2.深度优先遍历3.利用DFS判断有向图是否存在环4.广度优先遍历1.图的遍历 从图中某一顶点出发访问图中其余顶点,且每个顶点仅被访问一次 图的遍历有两种深度优先遍历...
    99+
    2024-04-02
  • MySQL由浅入深掌握连接查询
    目录内连接自然连接和等值连接的区别内连接的实现方式外连接左连接右连接全连接数据库版本:mysql8。0.27 内连接 内连接INNERJOIN是最常用的连接操作。从数学的角度讲就是求...
    99+
    2024-04-02
  • 由浅入深快速掌握Java 数组的使用
    目录1.数组定义格式1.1 数组概述1.2 什么是数组1.3 数组的定义格式:2.数组初始化之动态初始化2.1 数组初始化概述2.2 数组初始化方法3.数组元素访问3.1 数组元素访...
    99+
    2024-04-02
  • Golang包使用方法:由浅入深掌握
    从入门到精通:掌握Golang包的使用方法 引言:在现代软件开发领域,使用包(Package)是一种常见的组织和管理代码的方式。Golang作为一门高效、简洁的编程语言,也支持包的使用。本文将从入门到精通,详...
    99+
    2024-01-16
    Golang 入门 包使用
  • 深入浅析Java中线程池的原理
    这篇文章将为大家详细讲解有关深入浅析Java中线程池的原理,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。ThreadPoolExecutor简介ThreadPoolExecutor是线程池类...
    99+
    2023-05-31
    java ava 线程池
  • 深入浅出 Java 并发集合:掌握多线程编程的奥秘
    Java 并发集合简介 Java 并发集合是指可用于线程安全地存储和操作数据的集合类。这些集合类经过专门设计,确保在多线程环境下访问和修改数据时不会出现数据不一致或损坏的问题。 Java 并发集合的优点 使用 Java 并发集合具有以下...
    99+
    2024-02-07
    文章Java 并发集合 并发编程 线程安全 性能优化
  • Node.js PM2 部署指南:由浅入深,轻松掌握
    简介 PM2 是一个 Node.js 进程管理器,用于管理和监控多个 Node.js 应用程序。它提供了丰富的功能,如进程守护、日志记录、负载均衡和集群管理。本文将提供一份详细的指南,带你逐步了解如何使用 PM2 部署 Node.js ...
    99+
    2024-02-19
    Node.js PM2 部署 进程管理 应用程序部署
  • 深入浅出Node.js Socket.io库:从入门到精通
    Node.js Socket.io是一个即时双向通信库,使开发人员能够构建基于WebSockets(双向并双全工通信协议)的实时应用程序。它支持多种传输技术,包括WebSockets、轮询和长轮询,并提供了一系列功能,可帮助开发人员轻松...
    99+
    2024-02-11
    Node.js Socket.io 实时通信 WebSockets 聊天室
  • Java教程:从入门到精通,掌握对象容器的诀窍!
    Java是一种广泛使用的编程语言,由于其简单易学、可移植性好、高效可靠等特点,深受广大开发者的喜爱。在Java编程中,对象容器是非常重要的一部分。本文将从入门到精通,介绍Java中对象容器的相关知识,并演示一些常用的代码。 一、什么是对象...
    99+
    2023-08-01
    教程 对象 容器
  • Vue.js入门到精通:掌握WebSocket开发技巧
    Vue.js是一个强大的前端框架,以其轻量级、灵活性以及构建交互性应用程序的简便性而闻名。WebSocket是另一种在客户端和服务器之间建立双向通信渠道的技术,经常用于构建实时数据通信应用程序。 1. Vue.js入门 1.1 安装Vu...
    99+
    2024-02-12
    Vue.js WebSocket 实时通信 响应式编程
  • Java 深入浅出掌握Collection单列集合Set
    目录前言Set集合Set概述Set特点HashSet集合HashSet概述HashSet特点HashSet集合保证元素唯一性源码分析LinkedHashSet集合LinkedHash...
    99+
    2024-04-02
  • Java 容器框架教程:从入门到精通,一步步带你掌握!
    Java 是一门流行的编程语言,其容器框架是 Java 编程中最常用的工具之一。Java 容器框架提供了一组接口和类,可以存储和操作对象集合。这些容器包括 List、Set、Map 等。本教程将从 Java 容器框架的基础开始,一步步带你...
    99+
    2023-10-19
    容器 框架 教程
  • 从入门到精通,掌握Bash编程中的响应式技巧!
    Bash是一种非常强大的编程语言,可以帮助你在Linux系统中自动化许多任务。不仅如此,Bash还可以通过响应式编程技巧实现更高效的编程。在这篇文章中,我们将从入门到精通掌握Bash编程中的响应式技巧。 一、Bash的基础语法 在学习Bas...
    99+
    2023-08-08
    编程算法 bash 响应
  • Java线程同步与互斥:深入浅出,轻松掌握并发编程核心概念
    1. 线程同步与互斥概述 Java线程同步与互斥是指在多线程环境下,如何保证共享资源的访问和修改是安全的。线程同步可以防止多个线程同时访问同一个共享资源,从而避免数据不一致和程序崩溃。线程互斥进一步保证了只有一个线程能够访问某个共享资源...
    99+
    2024-02-09
    Java 线程 同步 互斥 并发编程 原子操作 可见性 有序性
  • Java 线程池:从概念到实现的深入探索
    线程池是一种管理线程集合的机制,它允许在应用程序中有效地利用线程资源。线程池减少了频繁创建和销毁线程的开销,从而提高了应用程序的性能和可扩展性。 主要功能 线程复用:线程池将线程预先创建并维护在一个池中,供任务使用,避免了重复创建线程的...
    99+
    2024-03-13
    线程池
  • 深入浅出 Node.js 事件驱动架构:从入门到精通
    Node.js 的事件循环机制是其事件驱动架构的基础,它负责接收和处理事件,并基于这些事件触发相应的回调函数。事件循环以单线程模式运作,即同时只处理一个事件,但它可以通过利用系统级的 I/O 操作来实现并发处理。 事件队列和事件循环:...
    99+
    2024-02-07
    事件循环机制:核心原理
  • Java 深入浅出掌握Map集合之双列集合
    目录前言Map集合Map概述Map特点Map集合的功能Map集合的遍历Map集合的各个子类集合框架图总结前言 友友们,大家好哇!这一期我为大家带来双列集合(Map)的相关知识点讲解,...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作