Java线程池及线程池工具类

线程池介绍

启动一个新线程涉及与操作系统交互,成本比较高。线程池在程序启动时创建大量空闲线程,程序将线程对象传给线程池,线程就会启动一个线程来执行它的run()或call()方法,方法执行结束后,线程并不会死亡,而是再次返回线程池中称为空闲状态,等待下一次执行。使用线程池可以避免频繁创建和销毁线程,可以使创建的线程得到复用,同时使用线程池可以有效控制系统中并发线程的数量。

线程池使用及参数介绍

线程池使用

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(参数);

public static void main(String[] args) {
        MyTestThreadPool myTestThreadPool = new MyTestThreadPool(3,3,0L,TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<>(10));

        for (int i = 0; i < 100; i++) {
            Runnable target = () -> {
                for (int j = 0; j < 10; j++) {
                    System.out.println("j = " + j);
                }
            };
            myTestThreadPool.submit(target);
        }
    }

线程池全参构造源码:

    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.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        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
任务队列,被提交到那时尚未被执行的任务
threadFactory
线程工厂,用于创建线程
handler
拒绝策略。当任务太多来不及处理时,如何拒绝任务。

等待队列

SynchronousQueue
SynchronousQueue没有容量,每一个put操作都需要等待一个对应的take操作。如果使用SynchronousQueue,则提交的任务不会被真实地保存,而是将新的任务提交给线程执行。
ArrayBlockingQueue
数组实现的有界阻塞队列,ArrayBlockingQueue的构造函数必须带参数,指定该队列的最大容量。此队列按照先进先出的顺序对元素进行排序。可以通过构造函数设定队列是否公平new ArrayBlockingQueue(int capacity, boolean fair)。默认情况下为非公平的访问队列。
LinkedBlockingQueue
LinkedBlockingQueue是基于链表实现。LinkedBlockingQueue中对生产者和消费者分别采用了独立的锁来控制数据同步,这也意味着在高并发情况下,生产者和消费者可以并行操作队列中的数据,提高整个队列的并发性能。
PriorityBlockingQueue
优先任务队列,带有执行优先级,可以控制任务执行的先后顺序。可以自定义是compareTo方法来实现排序,也可以指定构造参数Comparator来对数据进行排序。
DelayQueue
是一个支持延时获取元素的无界阻塞队列,队列使用PriorityQueue实现,队列中的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素。只有在延时期满时才能从队列中提取元素。

拒绝策略

JDK中内置的拒绝策略

当线程池中的任务数量超过负载时就会使用到拒绝策略。JDK中内置了四种拒绝策略:

  • AbortPolicy:该策略直接抛出异常,阻止线程继续工作;
  • CallerRunsPolicy:只要线程池未关闭,该策略直接在调用者线程中运行当前任务。这种方式可能造成任务提交线程的性能急剧下降;
  • DiscardOldestPolicy:该策略会丢弃最老的请求,也就是即将执行的一个任务,并尝试再次提交;
  • DiscardPolicy:该策略默认丢弃无法处理的任务。
自定义实现拒绝策略

自行扩展RejectedExecutionHandler接口。

线程池执行流程

简单描述: 核心线程(不满足时下一步,否则执行任务) -> 等待队列(不满足时下一步,否则执行任务) -> 非核心线程(不满足时下一步,否则执行任务) -> 拒绝策略。
具体步骤:

  • 当添加一个任务时,线程会做如下判断:
    (1)如果正在执行的线程数量小于corePoolSize,则马上创建线程执行这个任务;
    (2)如果正在执行的线程数量大于或等于corePoolSize,那么将这个任务放入等待队列;
    (3)如果队列满了,并且正在运行的线程数小于maximumPoolSize,则创建非核心线程处理该任务;
    (4)如果队列满了,并且正在运行的线程数大于或等于maximumPoolSize,则会抛出RejectedExecutionHandler(线程池设置的拒绝策略)。
  • 当一个线程完成任务时会到队列中取下一个任务来执行。
  • 当线程无事可做,超过设置等待时间,如果当前线程池线程数量大于maximumPoolSize,这个线程就会被干掉,线程池线程数量收缩到核心线程数大小。

线程池工具类创建线程池

java.util.concurrent.Executors工具类中提供了具有特定功能的线程池。

newFixedThreadPool

该方法创建一个可重用、有固定线程数量的线程池。该池中的线程数量始终不变。当有一个新任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被放入等待队列。

源码分析:

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

该线程池核心线程数与最大线程数相等,使用LinkedBlockingQueue作为等待队列,该队列的默认大小为Integer.MAX_VALUE,当任务提交非常频繁时,可能导致线程大量堆积。

newSingleThreadExecutor

该方法创建一个只有单线程的线程池,若提交任务时线程被詹总,则任务进入等待队列,待线程空闲,按照先进先出的顺序执行队列中的任务。
源码分析:

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

该线程池核心线程池与最大线程池数均为1,使用LinkedBlockingQueue作为等待队列,该队列的默认大小为Integer.MAX_VALUE,可能导致线程大量堆积。

newCachedThreadPool

该方法创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程会被缓存在线程池中。线程池中线程数量不确定,但若有空闲线程可以复用,会优先使用可复用的线程。若所有线程均在工作,则会创建新的线程处理任务。所有线程在当前线程执行完毕后,将返回线程池进行复用。
源码分析:

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

该线程池核心线程数为0,最大线程数为Integer.MAX_VALUE,使用了SynchronousQueue等待队列,该队列不存储任务,放入一个任务必须等待一个线程来处理任务。空闲线程会在60秒后被回收。使用该线程池,若同时有大量任务提交,而任务执行并不快,那么系统会创建大量线程来处理任务,这样做可能会很快耗尽系统资源。

newScheduledThreadPool

该方法创建具有指定线程数量的线程池,它可以在指定延迟后执行线程任务或周期性执行某个任务。该方法返回一个ScheduledExecutorService对象。
源码分析:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}

newSingleThreadScheduledExecutor

该方法返回ScheduledExecutorService对象,线程池的大小为1。
源码分析:

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1));
}

newWorkStealingPool

该方法床架持有足够线程的线程池来支持给定的并行级别,该方法还会使用多个队列来减少竞争。
源码分析:

    public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

自定义异常处理器

1、自定义线程池时重写protected void afterExecute(Runnable r, Throwable t)方法,对异常进行处理;
2、定义自己的异常处理器,通过Thread的setUncaughtExceptionHandler(new MyExHandler());方法,设置异常处理器。

class MyExHandler implements  Thread.UncaughtExceptionHandler{
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("线程" + t + "出现了异常:" + e);
    }
}
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
## iOS - 市面上最好用的数据库工具类 `XWDatabase` 开源##### [XWDatabase](https://github.com/qxuewei/XWDatabase) 将数据库操作简化到难以想象的程度,你甚至不需要知道数据库的存在,当然更不需要写 SQL 语句,你只需要直接操作模型即可对模型进行增删改查的操作,她会根据模型动态在数据库中创建以当前模型类名为名称的数据库表,当然你也可以自定义表名;她会根据模型的成员变量和成员变量的类型动态进行字段的设计,有多少成员变量,表中自然就会有多少字段与其对应,当然,你也可以忽略其中的某些你不想存储的成员变量,也可以自定义字段的名称;如果哪天模型的字段变化了,她会自动进行表中原有字段的更新,而且无论原表中有多少数据,都会一条不落的迁移到新表中;她的API简单到只有一行代码,你无需关注数据库的开启和关闭,一行代码实现增删改查和数据迁移; 你甚至可以在任何线程中调用她的API,她一定是线程安全的,不会出现多线程访问同一个数据库和死锁的问题;数据操作是耗时操作,所以你无需手动开启异步线程操作数据库操作,她会统一在一个保活的异步线程中执行;她支持存储常见的数据类型(int,long,signed,float,double,NSInteger,CGFloat,BOOL,NSString,NSMutableString,NSNumber,NSArray,NSMutableArray,NSDictionary,NSMutableDictionary,NSData,NSMutableData,UIImage,NSDate,NSURL,NSRange,CGRect,CGSize,CGPoint,自定义对象 等的存储.); 她还对二进制文件的存储做了优化,比如同一张图片表中所有数据都持有这张图片对象,她在数据库中只会有一份拷贝,竭尽她所能优化存储空间。 笔锋一转,V1.0 版本会存在很多不足,希望各位前辈和大牛多多指正,多提 `issues`项目源码开源在 GitHub 中,链接: [XWDatabase](https://github.com/qxuewei/XWDatabase)作者:极客学伟博客:
Hutool 是一个Java工具包,其中包含了许多方便实用的工具类,包括线程工具类。下面我们将使用300字回答如何使用Hutool线程工具。 Hutool提供了一些方便的方法来处理线程和线程池。首先,我们可以使用`ThreadUtil.sleep()`方法使当前线程休眠指定的时间,以便控制线程的执行时间。 另外,Hutool还提供了一些线程池工具类,如`ThreadFactoryBuilder`、`ExecutorBuilder`和`ScheduledExecutorBuilder`,使我们可以方便地创建线程池。 通过`ThreadFactoryBuilder`,我们可以自定义线程名称、线程优先级和线程组等信息来构建线程工厂。 通过`ExecutorBuilder`,我们可以创建自定义的线程池,可以设置核心线程数、最大线程数和线程存活时间等参数,以及自定义线程拒绝策略。 通过`ScheduledExecutorBuilder`,我们可以方便地创建定时执行任务的线程池,可以指定初始延迟时间和周期执行时间等参数。 使用Hutool线程工具,我们还可以方便地实现多线程的集合操作。例如,使用`ThreadUtil.execAsync()`方法可以创建多个线程并发执行,通过`ThreadUtil.join()`方法可以等待所有线程执行完毕。 此外,Hutool还提供了`Watcher`工具类,可以用于监控线程的状态和执行结果。 在使用Hutool线程工具时,我们需要先引入相关的依赖,然后根据需求选择合适的方法和工具类来处理线程和线程池操作。 总之,Hutool线程工具提供了许多方便实用的方法和工具类,可以帮助我们更轻松地处理线程和线程池的相关操作,提高开发效率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尘风-随手记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值