Java并发编程:线程池

1. 概述

1.1 线程池的特点

线程池 (Thread Pool) 是一种基于池化思想帮助我们管理线程而获取并发性的工具,经常出现在多线程服务器中,如 MySQL。线程池的实现思路:提前创建好多个线程,让这些线程处于就绪状态来提高系统响应速度,放入线程池中,使用时直接获取,使用完放回池中,可以避免频繁创建销毁,实现重复利用。

内存池 (Memory Pooling):预先申请内存,提升申请内存速度,减少内存碎片。
连接池 (Connection Pooling):预先申请数据库连接,提升申请连接的速度,降低系统的开销。
实例池 (Object Pooling):循环使用对象,减少资源在初始化和释放时的昂贵损耗。

  • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。(线程复用
  • 提高响应速度。当任务到达时,任务可以不需要等待线程创建就能立即执行。
  • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会因为线程的不合理分布,导致资源调度失衡,降低系统的稳定性。使用线程池可以进行统一的分配、调优和监控。(控制最大并发数
  • 提供更多更强大的功能:线程池具备可拓展性,允许开发人员向其中增加更多的功能。比如延时定时线程池 ScheduledThreadPoolExecutor 允许任务延期执行或定期执行。

1.2 异步回调

  • 同步和异步通常用来形容一次方法调用。
  • 同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为。
  • 异步方法调用一旦开始,方法调用就会立即返回,调用者就可以继续后续的操作。而异步方法通常会在另一个线程中“真实”地执行。整个过程,不会阻碍调用者的工作。对于调用者来说,异步调用似乎是一瞬间完成的。如果异步调用需要返回结果,那么当这个异步调用真实完成时,会通知调用者。
package com.java.forkjoinpool;

import java.util.concurrent.CompletableFuture;

/**
 * @author rrqstart
 * @Description 异步回调
 * public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {//......}
 */
public class CompletableFutureTest {
   
    public static void main(String[] args) throws Exception {
   
        //异步调用,无返回值,开启一个新线程来执行任务
        //public static CompletableFuture<Void> runAsync(Runnable runnable)
        CompletableFuture<Void> completableFuture1 = CompletableFuture.runAsync(() -> {
   
            System.out.println(Thread.currentThread().getName() + ":无返回值。");
        });
        Void v = completableFuture1.get();
        System.out.println(v); //null

        System.out.println("----------------------------------------");

        //异步回调,有返回值,开启一个新线程来执行任务
        //public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
        CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
   
            System.out.println(Thread.currentThread().getName() + ":有返回值。");
//            int i = 10 / 0;
            return 1024;
        });
        Integer i = completableFuture2.whenComplete((t, u) -> {
   
            System.out.println("t = " + t);
            System.out.println("u = " + u);
        }).exceptionally(f -> {
   
            System.out.println("exception : " + f.getMessage());
            return 404;
        }).get();
        System.out.println(i);
    }
}
//int i = 10 / 0;被注释掉时程序的输出结果:
ForkJoinPool.commonPool-worker-9:无返回值。
null
----------------------------------------
ForkJoinPool.commonPool-worker-9:有返回值。
t = 1024
u = null
1024
//int i = 10 / 0;没有被注释掉时程序的输出结果:
ForkJoinPool.commonPool-worker-9:无返回值。
null
----------------------------------------
ForkJoinPool.commonPool-worker-9:有返回值。
t = null
u = java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
exception : java.lang.ArithmeticException: / by zero
404

2. Executor框架

2.1 Executor框架简介

  • 在 Java 中,使用线程来异步的执行任务。Java 的线程既是工作单元,也是执行机制。从 JDK1.5 开始,把工作单元与执行机制分离开来,工作单元包括 Runnable 和 Callable,执行机制由 Executor 框架提供。
  • Executor 框架的两级调度模型
    • 在 HotSpot VM 的线程模型中,Java 线程被一对一映射为本地操作系统的线程。当 Java 线程启动时会创建一个本地操作系统线程;当该 Java 线程终止时,这个操作系统线程也会被回收。操作系统会调度所有线程并将它们分配给可用的CPU。
    • 在上层,Java 多线程程序通常把应用分解为若干个任务,然后使用用户级的调度器(Executor 框架)将这些任务映射为固定数量的线程;在底层,操作系统内核(OS Kernel)将这些线程映射到硬件处理器上。
  • Executor 框架的结构
    • 任务:包括被执行任务需要实现的接口 Runnable 和 Callable。
    • 任务的执行:包括任务执行机制的核心接口 Executor,以及继承自 Executor 的 ExecutorService 接口。
    • 异步计算的结果:包括接口 Future 和实现 Future 的 FutureTask 类。
    • ExecutorService 是真正的线程池接口,常见子类是 ThreadPoolExecutor。

2.2 Executors源码分析

package java.util.concurrent;
//Since:JDK1.5
public class Executors {
   
	//1.创建一个只有一个线程的线程池:一个任务一个任务的执行,适用于需要保证顺序的执行各个任务。
	public static ExecutorService newSingleThreadExecutor() {
   
        return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
    }
    
    //2.创建一个固定线程数的可重用的线程池:执行长期任务性能好,适合严格限制线程数的场景,如:负载比较重的服务器。
    public static ExecutorService newFixedThreadPool(int nThreads) {
   
    	//使用无界队列LinkedBlockingQueue(队列容量为:Integer.MAX_VALUE)作为线程池的工作队列
        return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
    }
    
    //3.创建一个线程数可伸缩的线程池:适用于执行很多短期异步任务,线程池根据需要创建新线程,但在先前构建的线程可用时将重启它们。可扩容!
    public static ExecutorService newCachedThreadPool() {
   
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
    }
	/**
	 * ScheduledThreadPoolExecutor继承自ThreadPoolExecutor。
	 * 表示在给定的延迟之后执行任务,或者定期执行任务。
	 * ScheduledThreadPoolExecutor的功能与Timer类似,但其功能更强大、更灵活。
	 * Timer对应的是单个后台线程,ScheduledThreadPoolExecutor可以对应1个或多个后台线程。
	 */
	//4.创建固定数量线程的线程池:适合多个后台线程执行周期任务,同时为了满足资源管理的需求而限制后台线程数量的场景。
	public static ScheduledExecutorService newScheduledThreadPool(int
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值