线程池的封装和使用

开发中你是否在用线程的时候一味的在new,这是很明显的弊端使用,项目中会有太多的地方需要线程,当你new了无数个线程时:
1.每次new Thread新建对象性能差

  • 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,即可能占用过多的系统资源导致死机(OOM)
    3.缺乏更多功能,比如定时执行,定期执行,线程中断
    二:## 线程池 ThreadPoolExecutor
    在 Java中 线程池的顶级接口 Executor这个接口。而Executor也也为我们创建了不同的线程池,想了解的小伙伴可以重点看下这个类。下面我们主要说的是ThreadPoolExecutor 类:

-首先看下它的构造函数:

五个参数:

 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)
//六个参数的构造函数-2
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler)
//七个参数的构造函数
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
  • 其次让我们看下这些参数代表的意思:

  • corePoolSize:线程池中的核心线程最大数。
    补充:核心线程:当线程池新建线程时候,若当前线程数小于corePoolSize,则创建的线程为核心线程。若超过则新建的为非核心线程。核心线程默认情况下会一直存活在线程池中,即使这个核心线程啥也不干(闲置状态)
    你如果看注释的话你发现还有一句话,如果指定的 ThreadPoolExecutor 的allowCoreThreadTimeOut 属性为true.那么核心线程如果闲置状态,超过一定时长(可设置),就会被销毁掉。

  • int maximumPoolSize
    线程池中线程总数的最大值
    线程总数=核心线程+非核心线程

  • long keepAliveTime
    线程池中非核心线程闲置超时时长。
    倘若设置allowCoreThreadTimeout=ture,则会作用于核心线程。

  • TimeUnit unit
    keepAliveTime的单位,TimeUnit是一个枚举类型,其包括:

    NANOSECONDS : 1微毫秒 = 1微秒 / 1000
    MICROSECONDS : 1微秒 = 1毫秒 / 1000
    MILLISECONDS : 1毫秒 = 1秒 /1000
    SECONDS : 秒
    MINUTES : 分
    HOURS : 小时
    DAYS : 天

  • BlockingQueue workQueue
    线程池中的任务队列:维护着等待执行的Runnable对象 当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务
    补充:
    常用的workQueue类型:
    1:SynchronousQueue:这个队列接收到任务的时候,会直接提交给线程处理,而不保留它,如果所有线程都在工作怎么办?那就新建一个线程来处理这个任务!所以为了保证不出现<线程数达到了maximumPoolSize而不能新建线程>的错误,使用这个类型队列的时候,maximumPoolSize一般指定成Integer.MAX_VALUE,即无限大
    :2:LinkedBlockingQueue:这个队列接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了maximumPoolSize的设定失效,因为总线程数永远不会超过corePoolSize
    3:ArrayBlockingQueue:可以限定队列的长度,接收到任务的时候,如果没有达到corePoolSize的值,则新建线程(核心线程)执行任务,如果达到了,则入队等候,如果队列已满,则新建线程(非核心线程)执行任务,又如果总线程数到了maximumPoolSize,并且队列也满了,则发生错误

4:DelayQueue:队列内元素必须实现Delayed接口,这就意味着你传进去的任务必须先实现Delayed接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务

RejectedExecutionHandler handler
,如果队列已满,则新建线程(非核心线程)执行任务,又如果总线程数到了maximumPoolSize,并且队列也满了,则发生错误。
会有一个默认的。
以上就是各参数的大体意思。接下来我们对ThreadPoolExecutor这个类做一下封装处理,方便我们调用:


import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 功能:线程池
 * 作者: YPU
 * 日期: 2019/6/23
 * 时间: 13:23
 */
public class ThreadManager {

    public static final String DEFAULT_SINGLE_POOL_NAME = "DEFAULT_SINGLE_POOL_NAME";

    private static ThreadPoolProxy mLongPool = null;
    private static Object mLongLock = new Object();

    private static ThreadPoolProxy mShortPool = null;
    private static Object mShortLock = new Object();

    private static ThreadPoolProxy mDownloadPool = null;
    private static Object mDownloadLock = new Object();

    private static Map<String, ThreadPoolProxy> mMap = new HashMap<String, ThreadPoolProxy>();
    private static Object mSingleLock = new Object();
    //==========================================================================
    // 构造方法
    //==========================================================================

    //==========================================================================
    // get、set方法
    //==========================================================================

    /**
     * 获取下载线程
     */
    public static ThreadPoolProxy getDownloadPool() {
        synchronized (mDownloadLock) {
            if (mDownloadPool == null) {
                mDownloadPool = new ThreadPoolProxy(3, 3, 5L);
            }
            return mDownloadPool;
        }
    }

    /**
     * 获取一个用于执行长耗时任务的线程池,避免和短耗时任务处在同一个队列而阻塞了重要的短耗时任务,通常用来联网操作
     */
    public static ThreadPoolProxy getLongPool() {
        synchronized (mLongLock) {
            if (mLongPool == null) {
                mLongPool = new ThreadPoolProxy(5, 5, 5L);
            }
            return mLongPool;
        }
    }
    /**
     * 获取一个用于执行短耗时任务的线程池,避免因为和耗时长的任务处在同一个队列而长时间得不到执行,通常用来执行本地的IO/SQL
     */
    public static ThreadPoolProxy getShortPool() {
        synchronized (mShortLock) {
            if (mShortPool == null) {
                mShortPool = new ThreadPoolProxy(2, 2, 5L);
            }
            return mShortPool;
        }
    }

    /**
     * 获取一个单线程池,所有任务将会被按照加入的顺序执行,免除了同步开销的问题
     */
    public static ThreadPoolProxy getSinglePool() {
        return getSinglePool(DEFAULT_SINGLE_POOL_NAME);
    }

    /**
     * 获取一个单线程池,所有任务将会被按照加入的顺序执行,免除了同步开销的问题
     */
    public static ThreadPoolProxy getSinglePool(String name) {
        synchronized (mSingleLock) {

            ThreadPoolProxy singlePool = mMap.get(name);
            if (singlePool == null) {
                singlePool = new ThreadPoolProxy(1, 1, 5L);
                mMap.put(name, singlePool);
            }
            return singlePool;
        }
    }

    //==========================================================================
    // 内部类、内部接口
    //==========================================================================

    public static class ThreadPoolProxy {
        private ThreadPoolExecutor mPool;
        private int mCorePoolSize;
        private int mMaximumPoolSize;
        private long mKeepAliveTime;

        private ThreadPoolProxy(int corePoolSize, int maximumPoolSize, long keepAliveTime) {
            mCorePoolSize = corePoolSize;
            mMaximumPoolSize = maximumPoolSize;
            mKeepAliveTime = keepAliveTime;
        }

        /**
         * 执行任务,当线程池处于关闭,将会重新创建新的线程池
         */
        public synchronized void execute(Runnable run) {
            if (run == null) {
                return;
            }
            if (mPool == null || mPool.isShutdown()) {
                mPool = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, mKeepAliveTime, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());


            }
            mPool.execute(run);
        }

        /**
         * 取消线程池中某个还未执行的任务
         */
        public synchronized void cancel(Runnable run) {
            if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
                mPool.getQueue().remove(run);
            }
        }

        /**
         * 取消线程池中某个还未执行的任务
         */
        public synchronized boolean contains(Runnable run) {
            if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
                return mPool.getQueue().contains(run);
            } else {
                return false;
            }
        }
        /**
         * 立刻关闭线程池,并且正在执行的任务也将会被中断
         */
        public void stop() {
            if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
                mPool.shutdownNow();
            }
        }
        /**
         * 平缓关闭单任务线程池,但是会确保所有已经加入的任务都将会被执行完毕才关闭
         */
        public synchronized void shutdown() {
            if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
                mPool.shutdownNow();
            }
        }
    }

调用:
通过 ThreadManager.getLongPool().excute调用

结语:本文章借鉴
https://www.jianshu.com/p/210eab345423

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
面向对象的线程池封装和基于对象的线程池封装有一些区别。下面是对它们的详细解释: 1. 面向对象的线程池封装: 面向对象的线程池封装通常是通过定义一个线程池类,该类封装线程池的管理和调度逻辑。这种封装方式通常使用类的成员函数来表示要执行的任务,并使用类的成员变量来存储线程池的状态和相关数据。 这种封装方式将线程池作为一个整体进行管理,通过调用类的方法来提交任务、获取任务执行结果等。线程池类通常会提供一些公共接口,比如启动线程池、停止线程池、添加任务等,以方便用户使用。 2. 基于对象的线程池封装: 基于对象的线程池封装通常是通过定义一个任务类,该类封装了要执行的任务逻辑,并使用线程池对象来管理和调度任务的执行。这种封装方式将任务作为一个独立的对象进行管理,每个任务对象都可以由线程池执行。 这种封装方式中,线程池对象负责维护一组线程,并提供一些接口供用户提交任务。任务对象通常实现了某个接口或继承了某个基类,以便线程池对象可以通过接口或基类来执行任务的逻辑。 总结区别如下: - 面向对象的线程池封装线程池作为一个整体进行管理,通过类的方法来提交任务和管理线程池。 - 基于对象的线程池封装将任务作为独立的对象进行管理,通过线程池对象来调度任务的执行。 需要注意的是,这两种封装方式都可以实现线程池的功能,具体选择哪种方式可以根据实际需求和设计风格来决定。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值