IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> JUC之线程池详解 -> 正文阅读

[Java知识库]JUC之线程池详解

一、为什么需要线程池:

多线程的异步执行方式,虽然能够最大限度发挥多核计算机的计算能力,但是如果不加控制,反而会对系统造成负担。线程本身也要占用内存空间,大量的线程会占用内存资源并且可能会导致Out of Memory。即便没有这样的情况,大量的线程回收也会给GC带来很大的压力。

为了避免重复的创建线程,线程池的出现可以让线程进行复用。通俗点讲,当有工作来,就会向线程池拿一个线程,当工作完成后,并不是直接关闭线程,而是将这个线程归还给线程池供其他任务使用。

二、线程池的简介:

线程池(英语:thread pool):一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度

线程池顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。

线程池做的工作主要是控制运行的线程的数量,处理过程中将任务加入队列,然后在线程创建后启动这些任务,如果线程数超过了最大数量,超出的数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。

线程池的主要特点为:线程复用、控制最大并发数、管理线程。
在这里插入图片描述

三、使用线程池有哪些优势:

  • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

  • 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。

  • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统 的稳定性,使用线程池可以进行统一的分配,调优和监控。

  • 附加功能:提供定时执行、定期执行、单线程、并发数控制等功能。

四、线程池架构:

在这里插入图片描述

shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务

shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务

五、线程池的使用:

Executors 是一个工厂类,主要用来创建 ExecutorService:
Java在JDK1.5之后,Java就包装了一个实现线程池的一个工厂类Executors,该工厂类有多个静态的方法newFixedThreadPool等。

Java 5+中的 Executor 接口定义一个执行线程的工具。它的子类型即线程池接口是 ExecutorService。

在这里插入图片描述
1.创建固定数量线程的线程池

newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。如果希望在服务器上使用线程池,建议使用 newFixedThreadPool方法来创建线程池,这样能获得更好的性能。

package com.fan.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPollTest {
    public static void main(String[] args) {
        //一池5线程,使用线程的工具类Executors创建线程
        ExecutorService threadPool1 = Executors.newFixedThreadPool(5);
        try {
            //10个顾客请求
            for (int i = 1; i <= 10; i++) {
                //执行  Runable接口
                threadPool1.execute(()->{
                    System.out.println(Thread.currentThread().getName()+
                            "办理业务");
                });
            }//end-for
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            threadPool1.shutdown();//关闭
        }

    }
}

在这里插入图片描述

2.创建只有一个线程的 线程池
Executors.newSingleThreadExecutor()方法
newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

package com.fan.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPollTest {
    public static void main(String[] args) {
    
        //一池一线程
        ExecutorService threadPool2 = Executors.newSingleThreadExecutor();

        try {
            //10个顾客请求
            for (int i = 1; i <= 10; i++) {
                //执行  Runable接口
                threadPool2.execute(()->{
                    System.out.println(Thread.currentThread().getName()+
                            "办理业务");
                });
            }//end-for
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            threadPool2.shutdown();//关闭
        }

    }
}

3.创建一池可扩容的线程

newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60 秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说 JVM)能够创建的最大线程大小。

源码:

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
 }

th

package com.fan.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPollTest {
    public static void main(String[] args) {
        //一池5线程
        //ExecutorService threadPool1 = Executors.newFixedThreadPool(5);
        //一池一线程
        //ExecutorService threadPool2 = Executors.newSingleThreadExecutor();
        //一池可扩容的线程
        ExecutorService threadPool3 = Executors.newCachedThreadPool();
        try {
            //20个顾客请求
            for (int i = 1; i <= 20; i++) {
                //执行  Runable接口
                threadPool3.execute(()->{
                    System.out.println(Thread.currentThread().getName()+
                            "办理业务");
                });
            }//end-for
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            threadPool3.shutdown();//关闭
        }

    }
}

4.newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求

线程池都有哪些状态:

RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。
SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务。
STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。
TIDYING:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated()。
TERMINATED(终结):terminated()方法结束后,线程池的状态就会变成这个。

线程池之ThreadPoolExecutor详解:

《阿里巴巴Java开发手册》中强制线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险.

Executors 各个方法的弊端:

  1. newFixedThreadPool 和 newSingleThreadExecutor:
    主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至 OOM。

  2. newCachedThreadPool 和 newScheduledThreadPool:
    主要问题是线程数最大数是 Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至 OOM。

ThreadPoolExecutor() 是最原始的线程池创建,也是阿里巴巴 Java 开发手册中明确规范的创建线程池的方式
ThreadPoolExecutor线程池的7大参数:

创建一个线程池时的参数:

  1. corePoolSize 表示线程池中的常驻核心线程数
    当提交一个任务到线程池的时候,线程池将会创建一个线程来执行任务。这个值的大小设置非常关键,设置过小将频繁地创建或销毁线程,设置过大则会造成资源浪费。
    线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程;如果超过corePoolSize,则新建的是非核心线程。

  2. maximumPoolSize 表示线程池能够容纳的同时执行的最大线程数
    如果队列(workQueue))满了,并且已创建的线程数小于 maximumPoolSize,则线程池会进行创建新的线程执行任务。 如果等待执行的线程数 大于 maximumPoolSize,缓存在队列中; 如果 maximumPoolSize 等于 corePoolSize,即是固定大小线程池。

  3. keepAliveTime 表示线程活动的保持时间
    当需要执行的任务很多,线程池的线程数大于核心池的大小时,keepAliveTime才起作用;
    当一个非核心线程,如果不干活(闲置状态)的时长超过这个参数所设定的时长,就会被销毁掉。

  4. TimeUnit :keepAliveTime 的单位
    它的单位有:TimeUnit.DAYS,TimeUnit.HOURS,TimeUnit.MINUTES,TimeUnit.MILLISECONDS,TimeUnit.MICRODECONDS

  5. workQueue 表示线程池中存放被提交但尚未被执行的任务的队列,即用于存放线程任务的阻塞队列
    维护着等待执行的 Runnable对象。当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务。

  6. threadFactory 用于设置创建线程的工厂
    它用来给每个创建出来的线程设置一个名字,就可以知道线程任务是由哪个线程工厂产生的。

  7. handler 表示拒绝处理策略
    表示当线程队列满了并且工作线程大于等于线程池的最大线程数(maxnumPoolSize)时如何来拒绝。
    线程数量大于最大线程数,当超过workQueue的任务缓存区上限的时候,就可以调用该策略,这是一种简单的限流保护。
    在这里插入图片描述

在这里插入图片描述

四种拒绝策略

Discard:丢弃的意思
AbortPolicy:终止、中断策略
CallerRunsPolicy:调用者运行策略
在这里插入图片描述

在这里插入图片描述

线程池实现原理:

线程池的工作流程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

tidying:整理,收拾的意思,这里是收尾整理状态
TERMINATED(终结)

线程池状态变化:

在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:14:58  更:2022-03-08 22:18:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:30:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码