线程池的使用和原理

线程池的使用和原理

目录

一、线程池的作用

二、线程池的关系图

三、线程池的创建及参数

四、线程池的使用原理

五、线程池的使用

 

一、线程池的作用

随着cpu核数越来越多,不可避免的利用多线程技术以充分利用其计算能力。所以,多线程技术是服务端开发人员必须掌握的技术。线程的创建和销毁,都涉及到系统调用,比较消耗系统资源,所以就引入了线程池技术,线程池中有已经创建好的线程,可直接使用,并且使用完了,直接再次放回线程池,避免频繁的线程创建和销毁。

 

二、线程池的关键类的关系图

线程池的使用和原理

 

从上面可以看出Java的线程池主的实现类主要有两个类ThreadPoolExecutor和ForkJoinPool。

ForkJoinPool是Fork/Join框架下使用的一个线程池,一般情况下,我们使用的比较多的就是ThreadPoolExecutor。我们大多数时候创建线程池是通过Executors

三、线程池的创建和参数解析

先看一个参数最完整的创建线程池的构造方法

线程池的使用和原理

参数解析:

corePoolSize:线程池的核心线程数,说白了就是,即便是线程池里没有任何任务,也会有corePoolSize个线程在候着等任务。

maximumPoolSize:最大线程数,不管你提交多少任务,线程池里最多工作线程数就是maximumPoolSize。

keepAliveTime:线程的存活时间。当线程池里的线程数大于corePoolSize时,如果等了keepAliveTime时长还没有任务可执行,则线程退出。

unit:这个用来指定keepAliveTime的单位,比如秒:TimeUnit.SECONDS。

workQueue:一个阻塞队列,提交的任务将会被放到这个队列里。

threadFactory:线程工厂,用来创建线程,主要是为了给线程起名字,默认工厂的线程名字:pool-1-thread-3。

handler:拒绝策略,当线程池里线程被耗尽,且队列也满了的时候会调用。

 

线程池创建:

java.util.concurrent.Executosr是线程池的静态工厂,我们通常使用它方便地生产各种类型的线程池,主要的方法有四种:

1、newSingleThreadExecutor()——创建一个单线程的线程池

2、newFixedThreadPool(int n)——创建一个固定大小的线程池

3、newCachedThreadPool()——创建一个可缓存的线程池

4、newScheduledThreadPool()——创建一个固定线程数的线程池,支持定时及周期性执行后台任务。

 

(1)newSingleThreadExecutor()单线程数的线程池

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory));

最关键的是corePoolSize(核心线程数)参数和maximumPoolSize(最大线程数)两个参数都是1

(2)newFixedThreadPool()固定线程数的线程池

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>(),
                                  threadFactory);

可以看出corePoolSize(核心线程数)参数和maximumPoolSize(最大线程数)两个参数都是相等

(3)newCachedThreadPool()创建一个可以根据需要创建新线程的线程池,它是没有线程数量限制的

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

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

corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE(认为是无限大)keepAliveTime=60s,当60s秒后没有任务执行的线程将会退出,由于CachedThreadPool线程没有上线,无线创建线程需要大量的内存,需要谨慎使用

(4)newScheduledThreadPool():创建一个固定线程数的线程池,支持定时及周期性执行后台任务。这个用的比较少,就略过

四、线程池的运行原理

用一张图来描述线程池执行的流程

线程池的使用和原理

该图对应如下源码:

线程池的使用和原理

五、线程池使用

实例

(1)newSingleThreadExecutor

MyThread.java

public class MyThread extends Thread{
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println(Thread.currentThread().getName() + "正在执行。。。");
	}
}

ThreadPoolTest.java

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

public class ThreadPoolTest {

	public static void main(String[] args) {
        //创建一个可重用固定线程数的线程池
        ExecutorService pool = Executors. newSingleThreadExecutor();
        //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
        Thread t1 = new MyThread();
        Thread t2 = new MyThread();
        Thread t3 = new MyThread();
        Thread t4 = new MyThread();
        Thread t5 = new MyThread();
        //将线程放入池中进行执行
        pool.execute(t1);
        pool.execute(t2);
        pool.execute(t3);
        pool.execute(t4);
        pool.execute(t5);
        //关闭线程池
        pool.shutdown();
    }
}

运行结果:

线程池的使用和原理

(2)newFixedThreadPool

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

public class ThreadPoolTest {

	public static void main(String[] args) {
        //创建一个可重用固定线程数的线程池
        //ExecutorService pool = Executors. newSingleThreadExecutor();
        //固定线程池大小
        ExecutorService pool = Executors.newFixedThreadPool(2);
        //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
        Thread t1 = new MyThread();
        Thread t2 = new MyThread();
        Thread t3 = new MyThread();
        Thread t4 = new MyThread();
        Thread t5 = new MyThread();
        //将线程放入池中进行执行
        pool.execute(t1);
        pool.execute(t2);
        pool.execute(t3);
        pool.execute(t4);
        pool.execute(t5);
        //关闭线程池
        pool.shutdown();
    }
}

运行结果:

线程池的使用和原理

(3)newCachedThreadPool

根据上面一样,只修改一句话

//创建一个可重用固定线程数的线程池

ExecutorService pool = Executors.newCachedThreadPool();

运行结果:

线程池的使用和原理

好了,线程池的简单介绍先到这里,如有不对,请多多指教。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/111249.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • linux删除用户名命令,linux删除用户命令

    linux删除用户名命令,linux删除用户命令Linux下删除以后的时候我们需要通过相关的命令来实现。下面由学习啦小编为大家整理linux删除用户命令的相关知识,希望对大家有帮助!linux删除用户命令简介userdel是一个底层用于删除用户的工具。在Debian上,我们通常会使用deluser命令。userdel会查询系统账户文件,例如/etc/password和/etc/group。那么它会删除所有和用户名相关的条目。在…

    2022年6月8日
    37
  • JavaScript进阶之道

    JavaScript进阶之道

    2021年7月5日
    93
  • STM32学习笔记(超详细整理145个问题)

    STM32学习笔记(超详细整理145个问题)1、AHB系统总线分为APB1(36MHz)和APB2(72MHz),其中2&amp;gt;1,意思是APB2接高速设备;2、Stm32f10x.h相当于reg52.h(里面有基本的位操作定义),另一个为stm32f10x_conf.h专门控制外围器件的配置,也就是开关头文件的作用;3、HSEOsc(HighSpeedExternalOscillator)高速外部晶振,一般为8MHz,…

    2022年5月3日
    72
  • qq群大数据可视化查询_QQ数据库

    qq群大数据可视化查询_QQ数据库2009年QQ群关系数据库可视化查询器优化推广获客神器十年老数据库最近很多人问这个QQ群关系数据库的事儿,拉出来聊一聊,顺带做了部分优化之前这个是被很多大神玩丢下来的东西,近几年手游市场的兴起,又成了手游市场的获客神器2012年之前封存的群关系数据,收录了将近8000万条群组信息,包含各种行业群,交友群,游戏群,手游推广的主要客户群体还是来源于游戏相关的群。简单讲,就是通过QQ群关系数据库,获取十年前的端游客户,从而转化为手游的消费者。为何要用这么

    2022年10月2日
    6
  • Proteus仿真–51单片机最小系统

    Proteus仿真–51单片机最小系统1.单片机的最小系统是由组成单片机系统必需的一些元件构成的,除了单片机之外,还需要包括电源供电电路、时钟电路、复位电路。下面着重介绍时钟电路和复位电路。1)时钟电路单片机工作时,从取指令到译码再进行微操作,必须在时钟信号控制下才能有序地进行,时钟电路就是为单片机工作提供基本时钟的。单片机的时钟信号通常有两种产生方式:内部时钟方式和外部时钟方式。内部时钟方式的原理电路如图所示。在单片机XTAL1和XTAL2引脚上跨接上一个晶振和两个稳频电容,可以与单片机片内的电路构成一个稳定的自激振荡器。晶振的取值

    2022年6月23日
    27
  • Activiti6详细教程

    Activiti6详细教程一、为什么选择Activitiactiviti介绍Activiti是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理,工作流,服务协作等领域的一个开源,灵活的,易扩展的可执行流程语言框架。工作流引擎对比二、核心7大接口、28张表7大接口(一)7大接口RepositoryService:提供一系列管理流程部署和流程…

    2022年7月21日
    38

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号