• 自定义线程池


    四、自定义线程池
    public ThreadPoolExecutor(
    int corePoolSize, //核心线程数,new的时候直接初始化的线程数量
    int maxinumPoolSize, //最大线程数
    long keppAliveTime, //空闲时间
    TimeUnit unit, //时间单位
    BlockingQueue<Runnable> workQueue, //任务队列
    ThreadFactory threadFactory, //
    RejectedExecutionHandler handler //
    )
    这个构造方法对于队列是什么类型的比较关键
    在使用有界队列时,若有新的任务需要执行,如果线程池实际线程小于corePoolSize,
    则优先创建线程;若大于corePoolSize,则会将任务加入队列,若队列已满,则在总
    线程数不大于maxnumPoolSize的前提下,创建新的线程,若线程数大于maxmunPoolSize,
    则执行拒绝策略。或其他自定义方式。
    无界的任务队列时:LinkedBlockingQueue。与有界队列相比,除非系统资源耗尽,否则
    无界的任务队列不存在任务入队失败的情况。当有新任务到来,系统的线程数小于
    corePoolSize时,则新建线程执行任务。当达到corePoolSize后,就不会继续增加。
    若后续仍有新的任务加入,而没有空闲的线程资源,则任务直接进入队列等待。若任务
    创建和处理的速度差异很大,无界队列会保持快速增长,直至耗尽系统内存。
    JDK拒绝策略:
    AbortPolicy:直接抛出异常组织系统正常工作
    CallerRunsPolicy:只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务。
    DiscardOldestPolicy:丢弃最老的一个请求,尝试再次提交当前任务。
    DiscardPolocy:丢弃无法处理的任务,不给于任何处理。
    如果需要自定义拒绝策略可以实现RejectExecutionHandler接口。

    4.1有界队列的例子
    public class UseSizeQueue {
    public static void main(String[] args) {
    /**
    * 在使用有界队列时,若有新的任务需要执行,如果线程池实际线程数小于corePoolSize,则优先创建线程,
    * 若大于corePoolSize,则会将任务加入队列, 若队列已满,则在总线程数不大于maximumPoolSize的前提下,创建新的线程,
    * 若线程数大于maximumPoolSize,则执行拒绝策略。或其他自定义方式。

    */
    ThreadPoolExecutor pool = new ThreadPoolExecutor(1, // coreSize
    2, // MaxSize
    60, // 60
    TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3) // 指定一种队列(有界队列)
    , new MyRejected()
    );

    MyTask mt1 = new MyTask(1, "任务1");
    MyTask mt2 = new MyTask(2, "任务2");
    MyTask mt3 = new MyTask(3, "任务3");
    MyTask mt4 = new MyTask(4, "任务4");
    MyTask mt5 = new MyTask(5, "任务5");
    MyTask mt6 = new MyTask(6, "任务6");

    pool.execute(mt1);
    pool.execute(mt2);
    pool.execute(mt3);
    pool.execute(mt4);
    pool.execute(mt5);
    pool.execute(mt6);

    //调用线程池的shutdown方法,并不是直接这个线程池就销毁了
    //而是等到所有任务运行结束
    pool.shutdown();
    }
    }
    1.如果上述代码只有pool.execute(mt1);的话,那么输出是:run taskId =1,并且在5s之后程序停止,这就是第一种情况:
    在使用有界队列时,若有新的任务需要执行,如果线程池实际线程数小于corePoolSize,则优先创建线程。
    2.如果上述代码有
    pool.execute(mt1);
    pool.execute(mt2);
    两行,那么输出是:
    run taskId =1
    run taskId =2
    并且先输出run taskId=1等待5s之后输出run taskId =2,再等待5s之后程序停止,这就是第二种情况:
    若大于corePoolSize,则会将任务加入队列,
    3.如果上述代码有5行
    pool.execute(mt1);
    pool.execute(mt2);
    pool.execute(mt3);
    pool.execute(mt4);
    pool.execute(mt5);
    则输出是这样的:
    run taskId =1
    run taskId =5
    run taskId =2
    run taskId =3
    run taskId =4
    首先是1和5执行,然后经过5s后,2和3执行,在经过5s后4执行,然后经过5s后程序结束。
    这就是第三种情况:
    若队列已满,则在总线程数不大于maximumPoolSize的前提下,创建新的线程,
    4.如果代码有6行:
    pool.execute(mt1);
    pool.execute(mt2);
    pool.execute(mt3);
    pool.execute(mt4);
    pool.execute(mt5);
    pool.execute(mt6);
    执行效果是:
    自定义处理..
    run taskId =1
    当前被拒绝任务为:6
    run taskId =5
    run taskId =2
    run taskId =3
    run taskId =4
    也就是说,当6来的时候被拒绝了,这就是第四种情况:
    若线程数大于maximumPoolSize,则执行拒绝策略。或其他自定义方式。

    4.2无界队列的例子
    public class NoSizeQueue implements Runnable{

    private static AtomicInteger count = new AtomicInteger(0);

    public void run() {
    try {
    int temp = count.incrementAndGet();
    System.out.println("任务" + temp);
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }

    public static void main(String[] args) throws Exception{
    BlockingQueue<Runnable> queue = 
    new LinkedBlockingQueue<Runnable>();
    ExecutorService executor = new ThreadPoolExecutor(
    5, //core
    10, //max
    120L, //2fenzhong
    TimeUnit.SECONDS,
    queue);

    for(int i = 0 ; i < 20; i++){
    executor.execute(new NoSizeQueue());
    }
    Thread.sleep(1000);
    System.out.println("queue size:" + queue.size()); //10
    Thread.sleep(2000);
    }

    }
    执行的结果是:
    任务1
    任务2
    任务3
    任务5
    任务4
    queue size:15
    任务6
    任务7
    任务8
    任务9
    任务10
    任务11
    任务12
    任务13
    任务14
    任务15
    任务16
    任务17
    任务18
    任务19
    任务20
    先执行了前5个任务,然后休息了时间。然后又取出了5个任务,然后又取出了5个任务,最后又取出了5个任务
    最先前的5个任务到位后,因为当前线程数小于coreSize,所以就直接新建线程执行了。
    其他的后面的15个任务会加入到队列中,等待被执行。

    五、拒绝策略
    AbortPolicy:直接抛出异常组织系统正常工作,当前任务丢失了,但是队列中等到的任务继续执行。
    CallerRunsPolicy:只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务。
    如果需要自定义拒绝策略可以实现RejectExecutionHandler接口。
    public class MyRejected implements RejectedExecutionHandler{


    public MyRejected(){
    }
    //其中r就是线程对象MyTask的一个实例
    //executor就是当前的线程池对象
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
    System.out.println("自定义处理..");
    System.out.println("当前被拒绝任务为:" + r.toString());

    }

    }
    常用的拒绝策略是:写日志,然后写一个定时的job,读取log日志,然后重跑。
    或者向数据源发送拒绝消息

  • 相关阅读:
    html5+css3中的background: -moz-linear-gradient 用法 (转载)
    CentOS 安装Apache服务
    Linux 笔记
    CURL 笔记
    Spring Application Context文件没有提示功能解决方法
    LeetCode 389. Find the Difference
    LeetCode 104. Maximum Depth of Binary Tree
    LeetCode 520. Detect Capital
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode 136. Single Number
  • 原文地址:https://www.cnblogs.com/zhongshiqiang/p/6855582.html
Copyright © 2020-2023  润新知