`
youyu4
  • 浏览: 425483 次
社区版块
存档分类
最新评论

Java多线程之线程池概述

 
阅读更多

Java多线程之线程池

 

适用情况

 

  • 单个处理时间比较短
  • 将要处理的任务量比较大

 

 

好处

 

  • 线程重复使用
  • 减少多次创建和注销线程的开销

 

 

工作模型

 


 

    1. 线程池的工作模型主要两部分组成,一部分是运行Runnable的Thread对象,另一部分就是阻塞队列。

 

    2. 由线程池创建的Thread对象其内部的run方法会通过阻塞队列的take方法获取一个Runnable对象,然后执行这个Runnable对象的run方法(即,在Thread的run方法中调用Runnable对象的run方法)。

 

    3. 当Runnable对象的run方法执行完毕以后,Thread中的run方法又循环的从阻塞队列中获取下一个Runnable对象继续执行。

 

    4. 当需要向线程池提交任务时会调用阻塞队列的offer方法向队列的尾部添加任务。提交的任务实际上就是是Runnable对象或Callable对象。

 

 

 

 

线程池工作流程

  

 

  1. 核心线程数,在创建线程池的时候还没有初始化
  2. 提交任务时,先判断核心线程数是否已经到达上限,如果不是就创建线程
  3. 如果工作线程数大于核心线程数,且任务队列未满,就进入任务队列
  4. 如果工作线程数大于核心线程数,且任务队列已满,那看工作线程数是否小于最大线程数,如果小于则创建线程
  5. 如果工作线程等于最大线程数,就会通过Handler所指定的策略来执行任务

上面的工作流程是根据ThreadPoolExecutor而言的,其实线程池的工作流程还要根据选择的线程池种类而定。



 

 

 

参数配置

 

corePoolSize:核心线程数

 

  • 核心线程会一直存活,及时没有任务需要执行
  • 当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理
  • 设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭

 

queueCapacity:任务队列容量(阻塞队列)

 

  • 当核心线程数达到最大时,新任务会放在队列中排队等待执行

 

maxPoolSize:最大线程数

 

  • 当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
  • 当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常

 

keepAliveTime:线程空闲时间

 

  • 当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
  • 如果allowCoreThreadTimeout=true,则会直到线程数量=0

 

allowCoreThreadTimeout:允许核心线程超时

 

  • 这个值只设置true,false

 

rejectedExecutionHandler:任务拒绝处理器

 

下面两种情况会拒绝处理任务:

 

  • 当线程数已经达到maxPoolSize,且队列已满,会拒绝新任务
  • 当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务

几种拒绝任务的处理方式:

 

  • AbortPolicy(默认) 丢弃任务,抛运行时异常
  • CallerRunsPolicy 执行任务
  • DiscardPolicy 忽视,什么都不会发生
  • DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务

 

 

 

 

线程池种类

 

  • 固定数量线程池
  • 单一线程池:只有一个线程
  • 缓存线程池:线程池中的线程数量不固定,会根据需求改变
  • 计划任务调度线程池:用于执行计划,比如每五分钟执行一次
  • ThreadPoolExecutor

 

 

newFixedThreadPool

 

创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到任务队列中。

 

优缺点 

FixedThreadPool是一个典型且优秀的线程池,它具有线程池提高程序效率和节省创建线程时所耗的开销的优点。但是,在线程池空闲时,即线程池中没有可运行任务时,它不会释放工作线程,还会占用一定的系统资源。

 

代码

package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
  ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
  for (int i = 0; i < 10; i++) {
   final int index = i;
   fixedThreadPool.execute(new Runnable() {
    public void run() {
     try {
      System.out.println(index);
      Thread.sleep(2000);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    }
   });
  }
 }
}

 

 

 

newSingleThreadExecutor

 

创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。

 

优缺点
单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。

 

代码

package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
  ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
  for (int i = 0; i < 10; i++) {
   final int index = i;
   singleThreadExecutor.execute(new Runnable() {
    public void run() {
     try {
      System.out.println(index);
      Thread.sleep(2000);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    }
   });
  }
 }
}

 

 

 

newCachedThreadPool

 

创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

 

优缺点

  • 工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。
  • 如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。
  • 在使用CachedThreadPool时,一定要注意控制任务的数量,否则,由于大量线程同时运行,很有会造成系统瘫痪。

代码

package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
  ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
  for (int i = 0; i < 10; i++) {
   final int index = i;
   try {
    Thread.sleep(index * 1000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   cachedThreadPool.execute(new Runnable() {
    public void run() {
     System.out.println(index);
    }
   });
  }
 }
}

 

 

 

newScheduleThreadPool

 

创建一个定长的线程池,而且支持定时的以及周期性的任务执行。

 

延迟3秒执行,延迟执行示例代码如下:

package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
  ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
  scheduledThreadPool.schedule(new Runnable() {
   public void run() {
    System.out.println("delay 3 seconds");
   }
  }, 3, TimeUnit.SECONDS);
 }
}

 

表示延迟1秒后每3秒执行一次,定期执行示例代码如下:

package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
 public static void main(String[] args) {
  ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
  scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
   public void run() {
    System.out.println("delay 1 seconds, and excute every 3 seconds");
   }
  }, 1, 3, TimeUnit.SECONDS);
 }
}

 

 

 

ThreadPoolExecutor

 

这是我们最常用的线程池,是线程池接口ExecutorService的实现类,其实上面的4中线程池都是由这个实现类来实现。

 

代码

public class DiscardPolicyDemo {  

    private static final int THREADS_SIZE = 1;  
    private static final int CAPACITY = 1;  

    public static void main(String[] args) throws Exception {  

        // 创建线程池。线程池的"最大池大小"和"核心池大小"都为1(THREADS_SIZE),"线程池"的阻塞队列容量为1(CAPACITY)。  
        ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(CAPACITY));  
        // 设置线程池的拒绝策略为"丢弃"  
        pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());  

        // 新建10个任务,并将它们添加到线程池中。  
        for (int i = 0; i < 10; i++) {  
            Runnable myrun = new MyRunnable("task-"+i);  
            pool.execute(myrun);  
        }  
        // 关闭线程池  
        pool.shutdown();  
    }  
}

 

 

 

线程池拒绝策略

 

  • AbortPolicy(默认):如不能接收任务,抛异常
  • CallerRunsPolicy:~~~~~~~~,让调用的线程去完成
  • DiscardOldestPolicy:~~~~~~,则丢弃最老一个任务,由一个队列来维护
  • DiscardPolicy:~~~~~~~~~~~,丢弃任务

设置线程池拒绝策略

// 创建线程池。线程池的"最大池大小"和"核心池大小"都为1(THREADS_SIZE),"线程池"的阻塞队列容量为1(CAPACITY)。  
ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(CAPACITY));  
// 设置线程池的拒绝策略为"丢弃"  
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());

  

 

 

线程池优化需要考虑的因数

  • 并发数
  • 单次请求的执行时间

 

 

线程池初始化

  • 默认新创建线程池中没有线程,有任务后才创建
  • prestartCoreThread()初始化一个核心线程
  • prestartAllCoreThread()初始化所有核心线程

 

 

线程池关闭

  • shutdown(),等任务执行完再终止,不接受新任务
  • shutdownNow(),马上终止,打断正在执行的任务,清空缓存队列,返回未执行的任务

 

  • 大小: 70.7 KB
  • 大小: 132 KB
  • 大小: 70.3 KB
  • 大小: 72.8 KB
分享到:
评论

相关推荐

    java 多线程设计模式 进程详解

    《JAVA多线程设计模式》PDF 下载 《Java线程 高清晰中文第二版》中文第二版(PDF) 前言 第一章 线程简介 Java术语 线程概述 为什么要使用线程? 总结 第二章 Java线程API 通过Thread类创建线程 使用Runable接口...

    讲给女朋友听的java多线程(2万字深入理解多线程,有实例代码辅助理解)

    读完本文大概需要30分钟左右,本文有大量的实例代码和典型例题帮助大家理解java多线程。虽然多线程比较难以理解,仅靠一篇文章恐怕搞不定。但读完本文最起码能让你搞懂java多线程的70%以上,至于熟练运用,还是得...

    Java-并发(Concurrent)编程

    资源概要:1,多线程;2,synchronized;3,volatile;4,多线程在JVM中的实现原理剖析 导语: 什么是多线程? 多线程(multithreading)是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因...

    Java基础知识点总结.docx

    十二、 多线程★★★★ 39 为什么要使用多线程 39 创建线程和启动 39 线程的生命周期 44 线程管理 45 线程同步 49 线程通信 52 线程池 58 死锁 64 线程相关类 65 十三、 同步★★★★★ 67 十四、 Lock接口 70 十五...

    java并发编程理论基础精讲

    本资源为您提供了关于 Java 并发编程理论基础的精讲,涵盖了多线程编程的核心概念、基本原理以及在 Java 中的应用。通过深入学习,您将建立坚实的并发编程基础,能够更好地理解和应对多线程编程中的挑战。 并发编程...

    java并发编程综合讲解

    您将了解如何在多线程环境下安全地进行数据访问,以及如何避免并发访问所带来的问题。我们将详细介绍 JUC 提供的线程安全集合类,如 ConcurrentHashMap 和 ConcurrentLinkedQueue,以及它们在实际应用中的用法。 ...

    Java并发编程原理与实战

    了解多线程所带来的安全风险.mp4 从线程的优先级看饥饿问题.mp4 从Java字节码的角度看线程安全性问题.mp4 synchronized保证线程安全的原理(理论层面).mp4 synchronized保证线程安全的原理(jvm层面).mp4 单例问题...

    疯狂JAVA讲义

    第1章 Java概述 1 1.1 Java语言的发展简史 2 1.2 Java的竞争对手及各自优势 4 1.2.1 C#简介和优势 4 1.2.2 Ruby简介和优势 4 1.2.3 Python的简介和优势 5 1.3 Java程序运行机制 5 1.3.1 高级语言的运行机制 6...

    龙果java并发编程完整视频

    第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个阶段并推荐学习并发的资料 ...

    threadpool:C ++线程池库

    概述ThreadPool实现了一个有界线程池,该线程池具有最小的核心池大小,并且可以为空闲线程配置可保持活动状态; 那些熟悉Java 会发现熟悉的接口和语义。 其核心是预先分配的工作线程池。 如果有空闲工人可用,或者...

    龙果 java并发编程原理实战

    第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个阶段并推荐学习并发的资料 ...

    Java SE实践教程 pdf格式电子书 下载(四) 更新

    第3章 当一个变成多个——集合框架的基本概念 53 .3.1 讲解 54 3.1.1 集合概述 54 3.1.2 Collection接口 54 3.1.3 泛型(Generics) 56 3.1.4 Map接口 57 3.2 练习 59 3.2.1 创建课程管理系统 59 3.3 小结 ...

    Java 并发编程原理与实战视频

    第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个阶段并推荐学习并发的资料 ...

    Java SE实践教程 源代码 下载

    第3章 当一个变成多个——集合框架的基本概念 53 .3.1 讲解 54 3.1.1 集合概述 54 3.1.2 Collection接口 54 3.1.3 泛型(Generics) 56 3.1.4 Map接口 57 3.2 练习 59 3.2.1 创建课程管理系统 59 3.3 小结 ...

    java并发编程

    第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个阶段并推荐学习并发的资料 ...

Global site tag (gtag.js) - Google Analytics