Java线程池

线程池概述

通俗的讲,线程池就是一个池子,里面全是线程。目的是对线程进行统一管理,对线程进行复用,对线程数量进行控制,避免过多的线程导致系统缓慢。和线程池紧密关联的是阻塞队列,当线程池中线程全部属于活跃状态时,新进来的请求就需要放在阻塞队列中进行排队等待空闲的线程。

Java中线程池的顶级接口Executor:

public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}

传入一个Runnable对象,并进行执行。

Executors

Java中Executors类提供了许多便捷的方式来创建线程池。

FixedThreadPool:固定线程池。每当提交一个任务就创建一个线程并放入线程池,直到线程池中线程到达最大值,线程池不再变化,线程除非发生了错误不会被回收。当线程池中线程全部处于活跃状态时,有新的获取线程请求,会将其放入LinkedBlockingQueue阻塞队列中,其中阻塞队列无限大。初始化方法如下。

public static ExecutorService newFixedThreadPool(int nThreads) {  
    return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());  
}

CachedThreadPool:缓存线程池。如果请求线程池中有空闲线程就分配空闲线程,否则创建一个新的线程并放入线程池,线程池无上限(最大值为Integer最大值2147483647),当一个线程空闲时间超过60S就会被回收。初始化方法如下。

public static ExecutorService newCachedThreadPool() {
	return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
}

SingleThreadExecutor:单个线程的线程池。池中只有一个线程,可以用来执行一些有顺序要求的任务(串行执行),当池中县城发生错误时,会创建一个新的线程替代。初始化方法如下。

public static ExecutorService newSingleThreadExecutor() {
	return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
}

ScheduledThreadPool:定时任务线程池。创建一个固定长度线程池,并且可以以定时任务的方式运行任务。初始化方法如下。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
	return new ScheduledThreadPoolExecutor(corePoolSize);
}

SingleThreadScheduledExecutor:SingleThreadExecutor+ScheduledThreadPool。

ThreadPoolExecutor

我们可以发现,虽然Executors的FixedThreadPool和CachedThreadPool方法返回的都是一个ExecutorService,但是实际上都是一个ThreadPoolExecutor,实际上我们在使用线程池的时候,更加的推荐使用ThreadPoolExecutor,而不是使用Executors,使用ThreadPoolExecutor更加的灵活,方便定制化自己所需要的线程池,也能让自己对线程池的使用更加的透明。

1.ThreadPoolExecutor的最完全构造方法。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {...}

corePoolSize:线程池中核心线程大小,默认情况下,如果线程池中的线程数量小于等于corePoolSize,则就算线程超过了keepAliveTime也不会被回收。当一个线程池很少被使用到时,可以使用ThreadPoolExecutor.allowCoreThreadTimeOut(true),来开启超时回收核心线程。

maximumPoolSize:线程池最大大小。

keepAliveTime:线程池中线程最大空闲时间(线程空闲时间达到这个值,会被回收),结合TimeUnit使用。

unit:keepAliveTime的时间单位。

workQueue:线程池的阻塞队列(线程池中线程全部处于活跃状态时,新的任务会进入阻塞队列),通常的实现有LinkedBlockingQueue和ArrayBlockingQueue等。

threadFactory:线程工厂,创建线程的工厂,比如我们想要线程池中的线程命名定制化,就需要自己实现一个ThreadFactory。给上一个简单的NamedThreadFactory实现。

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public class NamedThreadFactory implements ThreadFactory {

    private static final AtomicInteger TOTAL_THREAD_NUMBER = new AtomicInteger(1);
    private final AtomicInteger thisThreadNumber;
    private final String threadPrefix;

    public NamedThreadFactory() {
        this("pool-" + TOTAL_THREAD_NUMBER.getAndIncrement());
    }

    public NamedThreadFactory(String prefix) {
        this.thisThreadNumber = new AtomicInteger(1);
        this.threadPrefix = prefix + "-thread-";
    }

    @Override
    public Thread newThread(Runnable runnable) {
        String name = this.threadPrefix + this.thisThreadNumber.getAndIncrement();
        return new Thread(runnable, name);
    }

}

handler:饱和策略,决定了,当阻塞队列被任务堆满时,新进来的任务会被如何处置。ThreadPoolExecutor提供了四种RejectedExecutionHandler的实现。

  • ThreadPoolExecutor.CallerRunsPolicy:即caller runs,当阻塞队列满了的时候,其他线程调用execute()方法不再使用线程池,而是直接在主线程(调用线程)执行。
  • ThreadPoolExecutor.AbortPolicy:即abort,当阻塞队列满了的时候,直接抛出RejectedExecutionException异常,拒绝该任务。
  • ThreadPoolExecutor.DiscardPolicy:即discard,当阻塞队列满了的时候,舍弃新的任务(直接忽略新的execute()),与AbortPolicy不同的是不会抛出异常。
  • ThreadPoolExecutor.DiscardOldestPolicy:即DiscardOldest,当阻塞队列满了的时候,舍弃阻塞队列中最早的任务,再将此任务放入队列。

如果上述几种策略不满足系统的需求,可以自己实现RejectedExecutionHandler接口创建自定义的策略。

2.ThreadPoolExecutor的构造后修改

ThreadPoolExecutor中除了BlockingQueue,其他的都可以通过setXXX方法,在ThreadPoolExecutor构造之后进行修改,如ThreadPoolExecutor.setCorePoolSize(int size);可以修改线程池核心线程大小。

3.关于SingleThreadExecutor

我们可以看到其实SingleThreadExecutor的创建中的FinalizableDelegatedExecutorService类中传入了new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

我们查看源码可以发现,FinalizableDelegatedExecutorService中是包装设计模式包装了ExecutorService,也就是说方法的最后执行者还是ThreadPoolExecutor,这一层包装的目的是不让这个线程池后期进行修改,因为我们上一节讲到ThreadPoolExecutor的构造中的参数都可以后期通过setXXX进行修改。

总的来说new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());和Executors.newSingleThreadExecutor的唯一区别就是,前者可以通过setXXX方式修改变成非单一线程的线程池,而后者无法进行修改。


关于ScheduledThreadPoolExecutor,暂时不进行介绍。上述内容参考《Java并发编程实战》,有兴趣的朋友可以去阅读一下这本书籍。

内容概要:本文档是一份关于交换路由配置的学习笔记,系统地介绍了网络设备的远程管理、交换机与路由器的核心配置技术。内容涵盖Telnet、SSH、Console三种远程控制方式的配置方法;详细讲解了VLAN划分原理及Access、Trunk、Hybrid端口的工作机制,以及端口镜像、端口汇聚、端口隔离等交换技术;深入解析了STP、MSTP、RSTP生成树协议的作用与配置步骤;在路由部分,涵盖了IP地址配置、DHCP服务部署(接口池与全局池)、NAT转换(静态与动态)、静态路由、RIP与OSPF动态路由协议的配置,并介绍了策略路由和ACL访问控制列表的应用;最后简要说明了华为防火墙的安全区域划分与基本安全策略配置。; 适合人群:具备一定网络基础知识,从事网络工程、运维或相关技术岗位1-3年的技术人员,以及准备参加HCIA/CCNA等认证考试的学习者。; 使用场景及目标:①掌握企业网络中常见的交换与路由配置技能,提升实际操作能力;②理解VLAN、STP、OSPF、NAT、ACL等核心技术原理并能独立完成中小型网络搭建与调试;③通过命令示例熟悉华为设备CLI配置逻辑,为项目实施和故障排查提供参考。; 阅读建议:此笔记以实用配置为主,建议结合模拟器(如eNSP或Packet Tracer)动手实践每一条命令,对照拓扑理解数据流向,重点关注VLAN间通信、路由选择机制、安全策略控制等关键环节,并注意不同设备型号间的命令差异。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值