线程池ThreadPool

线程池概念

线程频繁创建和关闭,比较耗费cpu性能,可以通过线程池来管理,类似数据库连接池一样的道理.
学习Java的线程池,必须先知道创建线程池的原始类和方法ThreadPoolExecutor

类继承关系
    public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
  • corePoolSize:线程池核心线程数,空闲也不会被销毁

  • maximumPoolSize:线程池最大线程数

  • keepAliveTime:超出corePoolSize数量的线程的保留时间

  • unit:keepAliveTime单位

  • workQueue:阻塞队列,存放来不及执行的线程

    • ArrayBlockingQueue:构造函数一定要传大小
    • LinkedBlockingQueue:构造函数不传大小会默认为(Integer.MAX_VALUE ),当大量请求任务时,容易造成 内存耗尽。
    • SynchronousQueue:同步队列,一个没有存储空间的阻塞队列,将任务同步交付给工作线程。
    • PriorityBlockingQueue : 优先队列
  • threadFactory:线程工厂,一般默认即可

  • handler:饱和策略

    • AbortPolicy(默认):直接抛弃
    • CallerRunsPolicy:用调用者的线程执行任务
    • DiscardOldestPolicy:抛弃队列中最久的任务
    • DiscardPolicy:抛弃当前任务

常用线程池和方法

线程池:

  • newFixedThreadPool 固定线程池,可控制线程最大并发数,超出线程在队列中等待。
  • newSingleThreadExecutor 单线程池,用唯一的工作线程来执行任务。
  • newCachedThreadPool 缓存线程池,灵活回收空闲线程。
  • newScheduledThreadPool 定长线程池,支持定时及周期性任务执行。

方法:

  • execute() 添加任务
  • submit() 提交任务
  • shutdown() 关闭线程池
  • shutdownNow() 立即关闭线程池

1.测试线程类


public class MyThread implements Runnable { private String curName; public MyThread() {
} public MyThread(String curName) {
this.curName = curName;
} public String getCurName() {
return curName;
} public void setCurName(String curName) {
this.curName = curName;
} public void run() {
System.out.println("=========>>>开始执行:"+new SimpleDateFormat("yyyy-MM-dd ahh:mm:ss").format(new Date() )+"<<<=========");
System.out.println(Thread.currentThread().getName()+": "+this.curName);
try {
Thread.sleep(2000);// 模拟线程执行时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

2.newFixedThreadPool固定线程池

初始化线程池大小为3,模拟10个线程并发场景

/**
* 测试:定长线程池
*/
public void fixedPool(){
ExecutorService pool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
// 添加任务
pool.execute(new MyThread("线程0"+i));
}
pool.shutdown();
}

 

3.newSingleThreadExecutor单线程池

按照顺序一个一个执行

/**
* 测试:单线程池
*/
public void singlePool(){
ExecutorService pool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
// 添加任务
pool.execute(new MyThread("线程0"+i));
}
pool.shutdown();
}

 

4.newCachedThreadPool缓存线程池

/**
* 测试:缓存线程池
*/
public void cachePool(){
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
// 添加任务
pool.execute(new MyThread("线程0"+i));
}
pool.shutdown();
}

 

5.newScheduledThreadPool定长线程池

线程池支持延时执行和周期执行

  • schedule(Callable callable, long delay, TimeUnit unit)延时执行
  • scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)延时固定间隔执行
  • scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)第一次执行完,延时固定间隔执行
/**
* 测试:定长线程池
*/
public void scheduledPool(){
ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
System.out.println("=========>>>启动线程池:"+new SimpleDateFormat("yyyy-MM-dd ahh:mm:ss").format(new Date() )+"<<<=========");
// 延时3秒执行
pool.schedule(new MyThread("线程01_延时"),3,TimeUnit.SECONDS);
// 延时5秒循环执行
pool.scheduleAtFixedRate(new MyThread("线程02_延时_循环"),5,5,TimeUnit.SECONDS);
pool.scheduleWithFixedDelay(new MyThread("线程03_延时_循环"),5,5,TimeUnit.SECONDS);
// 不关闭线程池
// pool.shutdown();
}

 

6.完整代码

package com.lyf.thread;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*; /**
* @author lyf
* @date 2019/8/11 11:03
*
* newFixedThreadPool 固定线程池,可控制线程最大并发数,超出线程在队列中等待。
* newSingleThreadExecutor 单线程池,用唯一的工作线程来执行任务。
* newCachedThreadPool 缓存线程池,灵活回收空闲线程。
* newScheduledThreadPool 定长线程池,支持定时及周期性任务执行。
* 常用方法:
* execute() 添加任务
* submit() 提交任务
* shutdown() 关闭线程池
* shutdownNow() 立即关闭线程池
*/ public class MyThread implements Runnable { private String curName; public MyThread() {
} public MyThread(String curName) {
this.curName = curName;
} public String getCurName() {
return curName;
} public void setCurName(String curName) {
this.curName = curName;
} public void run() {
System.out.println("=========>>>开始执行:"+new SimpleDateFormat("yyyy-MM-dd ahh:mm:ss").format(new Date() )+"<<<=========");
System.out.println(Thread.currentThread().getName()+": "+this.curName);
try {
Thread.sleep(2000);// 模拟线程执行时间
} catch (InterruptedException e) {
e.printStackTrace();
}
} /**
* 测试:固定线程池
*/
public void fixedPool(){
ExecutorService pool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
// 添加任务
pool.execute(new MyThread("线程0"+i));
}
pool.shutdown();
} /**
* 测试:单线程池
*/
public void singlePool(){
ExecutorService pool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
// 添加任务
pool.execute(new MyThread("线程0"+i));
}
pool.shutdown();
} /**
* 测试:缓存线程池
*/
public void cachePool(){
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
// 添加任务
pool.execute(new MyThread("线程0"+i));
}
pool.shutdown();
} /**
* 测试:定长线程池
*/
public void scheduledPool(){
ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
System.out.println("=========>>>启动线程池:"+new SimpleDateFormat("yyyy-MM-dd ahh:mm:ss").format(new Date() )+"<<<=========");
// 延时3秒执行
pool.schedule(new MyThread("线程01_延时"),3,TimeUnit.SECONDS);
// 延时5秒循环执行
pool.scheduleAtFixedRate(new MyThread("线程02_延时_循环"),5,5,TimeUnit.SECONDS);
pool.scheduleWithFixedDelay(new MyThread("线程03_延时_循环"),5,5,TimeUnit.SECONDS);
// 不关闭线程池
// pool.shutdown();
} public static void main(String []args) {
MyThread myThread = new MyThread();
// myThread.fixedPool();
// myThread.singlePool();
// myThread.cachePool();
myThread.scheduledPool();
} }

submit和execute方法区别

submit和execute方法都可以提交任务到线程池中,区别3点:

  1. 接收参数不一样,submit需要线程实现Callable接口
  2. submit有返回值,而execute没有
  3. submit可以处理线程内部异常
package com.lyf.thread;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*; class MyThread02 implements Callable<String> { @Override
public String call() throws Exception {
// 模拟3s~10s之间的延时和返回结果
long time = (long) (Math.random()*7+3);
Thread.sleep(time*1000);
String curName = Thread.currentThread().getName();
System.out.println("=========>>>执行完毕:"+new SimpleDateFormat("yyyy-MM-dd ahh:mm:ss").format(new Date() )+"<<<=========");
return curName+"_"+time;
} public static void main(String[] args) {
System.out.println("=========>>>启动线程池:"+new SimpleDateFormat("yyyy-MM-dd ahh:mm:ss").format(new Date() )+"<<<=========");
ExecutorService executorService2 = Executors.newFixedThreadPool(5);// 定长线程池
List<Future<String>> futureList = new ArrayList<>();//存储任务
for (int i = 0; i < 5; i++) {
Future<String> future = executorService2.submit(new MyThread02());
futureList.add(future);
}
for (int i = 0; i < 5; i++) {
Future<String> future = futureList.get(i);
try {
System.out.println("Result: " + future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
executorService2.shutdown();
}
}

线程池ThreadPool实战的更多相关文章

  1. 线程池ThreadPool的初探

    一.线程池的适用范围 在日常使用多线程开发的时候,一般都构造一个Thread示例,然后调用Start使之执行.如果一个线程它大部分时间花费在等待某个事件响应的发生然后才予以响应:或者如果在一定期间内重 ...

  2. C#多线程学习 之 线程池[ThreadPool](转)

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  3. 高效线程池(threadpool)的实现

    高效线程池(threadpool)的实现 Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线 ...

  4. 多线程系列 线程池ThreadPool

    上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...

  5. Spring线程池开发实战

    Spring线程池开发实战 作者:chszs,转载需注明. 作者博客主页:http://blog.csdn.net/chszs 本文提供了三个Spring多线程开发的例子,由浅入深,由于例子一目了然, ...

  6. C# -- 使用线程池 ThreadPool 执行多线程任务

    C# -- 使用线程池 ThreadPool 执行多线程任务 1. 使用线程池 class Program { static void Main(string[] args) { WaitCallba ...

  7. 多线程Thread,线程池ThreadPool

    首先我们先增加一个公用方法DoSomethingLong(string name),这个方法下面的举例中都有可能用到 #region Private Method /// <summary> ...

  8. C# 线程池ThreadPool的用法简析

    https://blog.csdn.net/smooth_tailor/article/details/52460566 什么是线程池?为什么要用线程池?怎么用线程池? 1. 什么是线程池? .NET ...

  9. 多线程系列(2)线程池ThreadPool

    上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...

随机推荐

  1. 从0开始部署GPU集群-1:k8s部署生态

    1 k8s:nvidia deepops 2  批处理:华为volcano 3 工作流:argo

  2. #C++初学记录(set进阶#acm cf 190802 B. Subsegments)

    B. Subsegments#set进阶 Programmer Sasha has recently begun to study data structures. His coach Stas to ...

  3. 菜鸟学IT之Hadoop综合大作业

    Hadoop综合大作业 作业来源:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/3363 1.将爬虫大作业产生的csv文件上传到HDF ...

  4. # 61条面向对象设计的经验原则-《OOD启思录》Arthur J.Riel

    61条面向对象设计的经验原则-<OOD启思录>Arthur J.Riel 原文 http://blog.csdn.net/cpluser/article/details/129291 61 ...

  5. 从安装PHP到第一个tomcat执行的hello world其实没那么难

    001 初入门的朋友问我为什么她的PHP老是不能安装运行成功,作为一个乐(shi)于(li)助(liao)人(mei)的半程序员, 自然是要好好研究然后手把手教妹纸了! 002 话不多说,进入正题 为 ...

  6. vue中使用极验验证码(附demo)

    前言: vue中使用极验验证码,最好是在页面渲染的时候(mounted)进行验证码的初始化,然后在初始化回调中绑定触发弹出验证码的事件.这样在点击按钮或者进行特定操作时能够快速的弹出验证码. 关键代码 ...

  7. 30段极简Python代码

    Python 是机器学习最广泛采用的编程语言,它最重要的优势在于编程的易用性.如果读者对基本的 Python 语法已经有一些了解,那么这篇文章可能会给你一些启发.作者简单概览了 30 段代码,它们都是 ...

  8. Ehcache API的使用和注意点

    目录 创建CacheManager CacheManager常用的API 创建Cache Cache常用的API 创建Element Element常用的API 配置文件 配置文件名为ehcache. ...

  9. Kafka在zookeeper中存储结构和查看方式

    Zookeeper 主要用来跟踪Kafka 集群中的节点状态, 以及Kafka Topic, message 等等其他信息. 同时, Kafka 依赖于Zookeeper, 没有Zookeeper 是 ...

  10. 【超分辨率】- CVPR2019中SR论文导读与剖析

    CVPR2019超分领域出现多篇更接近于真实世界原理的低分辨率和高分辨率图像对应的新思路.具体来说,以前论文训练数据主要使用的是人为的bicubic下采样得到的,网络倾向于学习bicubic下采样的逆 ...