线程池的使用和原理

线程池的使用和原理

目录

一、线程池的作用

二、线程池的关系图

三、线程池的创建及参数

四、线程池的使用原理

五、线程池的使用

 

一、线程池的作用

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

相关推荐

  • idea激活码在哪输入(注册激活)「建议收藏」

    (idea激活码在哪输入)本文适用于JetBrains家族所有ide,包括IntelliJidea,phpstorm,webstorm,pycharm,datagrip等。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/ide…

    2022年3月26日
  • android 电平信号状态识别View平局

    android 电平信号状态识别View平局

    2022年1月9日
  • 滑动窗口求最大值 leetcode 59

    滑动窗口求最大值 leetcode 59滑动窗口最大值问题利用递减队列实现Dequeuedequeue=newLinkedList<>();递减队列方法说明peekFirst获取队头元素pollFirsr队头元素出队offerLast==add在队尾插入新元素publicint[]maxSlidingWindow(int[]nums,intk){if(nums.length==0){returnnewint[0];}

    2022年7月13日
  • 网页视频下载(TS流下载合成)

    网页视频下载(TS流下载合成)前言最近《流浪地球》比较火,想找资源下载看看,无奈只找到了网址http://m.tlyy.tv/,但是我的chrome插件也嗅探不到网页上的视频。。于是乎,右击页面,inspect走起…步骤首先发现m3u8文件映入眼帘/偷笑,m3u8文件是什么文件呢,copyaddressandwget下来看看:文件playlist.m3u8内容如下,可见网页里的视频是根据这个play…

    2022年7月18日
  • dos的批量copy命令

    dos的批量copy命令1、主要是有需求,采取百度的,发现挺好的,还是帮作者推广一下。来自https://www.cnblogs.com/xiykj/archive/2004/01/13/13299548.html“Dos命令复制所有目录下同类型文件”2、需求:想拷贝文件夹内部的同类型文件(比如*.jpg),但是这个jpg文件在不同的文件夹下面,因此copy起来还是不方便,因此需要寻求命令代码解决3、命令是:for/r%iin(.jpg)*docopy“%i”/yd:\img其中,加粗的是变成自己需

    2022年7月18日
  • Ubuntu 安装 yum

    Ubuntu 安装 yum120@110:~$sudoapt-getinstallyum120@110:~$aliasyum=’sudoapt-get’120@110:~$yuminstall119正在读取监狱室列表…完成正在分析监狱头犯的依赖关系树正在读取状态信息…完成

    2022年6月16日

发表回复

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

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