线程池的使用和原理

线程池的使用和原理

目录

一、线程池的作用

二、线程池的关系图

三、线程池的创建及参数

四、线程池的使用原理

五、线程池的使用

 

一、线程池的作用

随着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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java 开发中 dom4j的简单用法「建议收藏」

    java 开发中 dom4j的简单用法「建议收藏」Java中处理XML的方式有很多种,个人任务dom4j还是比较好用的。下面介绍以下简单的使用方法先把import补充上1.首先我们一般会先根据各种方式得到一个xml格式的字符串或者文件,例如:

    2022年7月4日
    33
  • sqlyog安装步骤_sqlyog安装教程

    sqlyog安装步骤_sqlyog安装教程百度网盘账号(QQ账号):374879539QQ密码:fjl12345进去下载SQLyog的安装包就可以了用完之后及得给我的博客点个赞和关注哦!

    2022年9月24日
    0
  • 【赠书】深入浅出Python量化交易实战

    【赠书】深入浅出Python量化交易实战‍‍本书主要以国内A股市场为例,借助第三方量化交易平台,讲述了KNN、线性模型、决策树、支持向量机、朴素贝叶斯等常见机器学习算法在交易策略中的应用,同时展示了如何对策略进行回测,以便让读者…

    2022年10月18日
    0
  • linux安装pycharm详细步骤[通俗易懂]

    linux安装pycharm详细步骤[通俗易懂]一、用xftp远程根据把解压后的安装包文件上传到指定目录/opt/module/。然后,cd/opt/pycharm-community-linux-2018.1.4/bin/,执行以下代码赋予pycharm.sh执行权限[atguigu@hadoop101bin]$chmodu+xpycharm.sh最后,执行$shpycharm.sh启动pycharm[atguigu@hadoop101bin]$pycharm.shStartupError:Unab…

    2022年8月25日
    4
  • oracle+mybatis分页查询

    oracle+mybatis分页查询当使用oracle进行分页查询时使用以下方式:SELECT* FROM(SELECTA.*,ROWNUMRN     FROM(selectt.name   asname,           t.formula asformula,           t.data_fromasdataFro

    2022年5月6日
    38
  • Linux安装NVIDIA显卡驱动的正确姿势

    Linux安装NVIDIA显卡驱动的正确姿势什么是nouveau驱动?检测NVIDIA驱动是否成功安装集显与独显的切换使用标准仓库进行自动化安装使用PPA仓库进行自动化安装使用官方的NVIDIA驱动进行手动安装Linux安装NVIDIA显卡驱动的正确姿势可能想玩Linux系统的童鞋,往往死在安装NVIDIA显卡驱动上,所以这篇文章帮助大家以正常的方式安装NVI…

    2022年4月7日
    179

发表回复

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

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