Java多线程学习笔记5——ThreadPoolExecutor

阿里代码规范中规定,线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程。这样做的好处是减少在创建和销毁所花的时间和系统开销。不使用线程池可能造成创建大量同类线程而导致消耗内存或则“过度切换”的问题。并且规定线程池不允许使用Executors创建。那么创建线程的方式基本就依赖于ThreadPoolExecutor此类了。

先了解下ThreadPoolExecutor的构造函数:

//构造函数使用默认的  DefaultThreadFactory  以及默认的AbortPolicy
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,   long keepAliveTime,  TimeUnit unit, 
                                                                                  BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler);
 }
   //使用默认的拒绝策略
    public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,  long keepAliveTime,  TimeUnit unit,
                              BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler);
    }
    //以上两个两个构造函数调用此函数
    public ThreadPoolExecutor(int corePoolSize,   int maximumPoolSize,   long keepAliveTime, TimeUnit unit,
                          BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
           this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), handler);
    }

   //以上三个函数调用此函数
    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;
    }

以上Overloading最终调用最后一个函数,集中解析下最后一个构造函数的参数就可以了。

new  ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler)

corepoolsize:核心线程数   线程池创建后激活的线程数量

maxinumpoolSize:最大线程数  线程池提交的线程数,如果队列已经满了,而且超出最大线程数,会使用拒绝策略

keepAliveTime和timeUnit配置使用表示超过核心线程数的线程最大的空闲存货时间和单位

blockingQueue:保存等待执行的任务的阻塞队列 参数可以如下

ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,按FIFO原则进行排序
LinkedBlockingQueue:一个基于链表结构的阻塞队列,吞吐量高于ArrayBlockingQueue。
SynchronousQueue: 一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量高于LinkedBlockingQueue。
PriorityBlockingQueue:一个具有优先级的无限阻塞队列。

threadFactory:通过线程工厂为每个创建出来的线程设置更有意义的名字

RejectedExecutionHandler:当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略还处理新提交的任务。它可以有如下四个选项:
AbortPolicy:直接抛出异常,默认情况下采用这种策略
CallerRunsPolicy:只用调用者所在线程来运行任务
DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务
DiscardPolicy:不处理,丢弃掉

     有了以上定义好的数据,下面来看看内部是如何实现的 。整个思路总结起来就是 5 句话:

  1. 如果当前池大小 poolSize 小于 corePoolSize ,则创建新线程执行任务。
  2. 如果当前池大小 poolSize 大于 corePoolSize ,且等待队列未满,则进入等待队列
  3. 如果当前池大小 poolSize 大于 corePoolSize 且小于 maximumPoolSize ,且等待队列已满,则创建新线程执行任务。
  4. 如果当前池大小 poolSize 大于 corePoolSize 且大于 maximumPoolSize ,且等待队列已满,则调用拒绝策略来处理该任务。
  5. 线程池里的每个线程执行完任务后不会立刻退出,而是会去检查下等待队列里是否还有线程任务需要执行,如果在 keepAliveTime 里等不到新的任务了,那么线程就会退出。

 

我们看下常用Executors的实现:

 //固定大小的线程池,多余的线程放入linkedBlockingQueue中,然后从对列中取线程
 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
//synchronousQueue不存储元素,有元素立即分配线程   
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
//其实就是单位为1的fixedThreaPool    
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

看了这么多实例我们可知,以上线程池如果线程过多可能会造成大量堆积待处理线程或则创建大量线程的问题。灵活使用ThreadPoolExecutor可以更加明确线程运行规则,避免资源耗尽的风险。

欢迎留言交流,共同讨论

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像识别技术在病虫害检测中的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分类植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物图像数据,这些数据包括健康植物的图像以及受不同病虫害影响的植物图像。 2. **图像预处理**:对收集到的图像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从图像中提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程中,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统中,可以是移动应用、网页服务或集成到智能农业设备中。 7. **实时监测**:在实际应用中,系统可以实时接收植物图像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,图像识别在病虫害检测中的应用将越来越广泛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值