线程池的使用和原理

线程池的使用和原理

目录

一、线程池的作用

二、线程池的关系图

三、线程池的创建及参数

四、线程池的使用原理

五、线程池的使用

 

一、线程池的作用

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


相关推荐

  • 破解Navicat提示生成激活码错误(注册激活)2022.02.27

    (破解Navicat提示生成激活码错误)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

    2022年4月1日
  • luke的使用[通俗易懂]

    luke的使用[通俗易懂]zz网络首次用Luke打开索引文件。Overview里面显示了索引具有的Field数目(以最大的Field为准吧?),还有就是文档的总数和Term即索引词的总数?有时一个关键词,对应于多个文档,所

    2022年8月6日
  • ssl协议及开源实现openssl

    ssl协议及开源实现opensslssl协议SSL:(SecureSocketLayer)安全套接层,ssl是一套安全协议,被应用层调用,当http调用ssl协议时被称为https,当ftp调用ssl协议时被称为sftp。lls是一个协议的集合,其中包括:Handshake协议:包括协商安全参数和密码套件、服务器身份认证(客户端身份认证可选)、密钥交换ChangeCipherSpec协议:一条消息表明握手协议已

    2022年5月11日
  • pycharm删除的文件 找回_pycharm重命名

    pycharm删除的文件 找回_pycharm重命名1、打开pycharm后,点击项目文件夹右键2、在弹出的菜单中,点击LocalHistory,会自动出现子菜单,点击showhistoy功能;3、弹出本地历史窗口后,左侧显示删除的文件列表及信息(文件名及删除时间;4、选中需要找回的文件后,点击右键,选择Revertselection…

    2022年8月26日
  • C++ offsetof

    C++ offsetof这是一个宏,用于计算类中某个成员的地址相对于类实例的偏移量在C++11中,要求这个类standard_layout基本用法是这样子的:#include<stdio.h>/*printf*/#include<stddef.h>/*offsetof*/structfoo{chara;ch…

    2022年8月22日
  • 关于模板函数声明与定义的问题[通俗易懂]

    c++primer上说:c++模板函数的声明与定义通常放在头文件中,而普通的函数通常是声明放在头文件中,定义放在源文件中,为什么会有这样的区别呢?模板函数与普通成员函数到底有什么区别?测试代码:tem.h#ifndef_TEM_H#define_TEM_HtemplateTadd(Ta,Tb);//{//returna+b;//}

    2022年4月17日

发表回复

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

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