ThreadPoolExecutor高级应用

自定义线程池队列的选择

  • 使用有界队列(ArrayBlockingQueue)自定义线程池,当任务的数量小于corePoolSize的时候,直接创建新的线程执行任务。当任务数量大于corePoolSize的时候会将任务加入到等待队列。若等待队列已满再不大于maxPoolSize的情况下直接创建新的线程执行任务。
package threadpool;

import java.util.Calendar;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyThreadPool {

    public static void main(String[] args) {
         BlockingQueue<Runnable> queue =
                 new  ArrayBlockingQueue<Runnable>(3);
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                1, // corePoolSize
                2, // maxPoolSize
                60, TimeUnit.SECONDS, queue);
        Task t1 = new Task(1);
        Task t2 = new Task(2);
        Task t3 = new Task(3);
        Task t4 = new Task(4);
        Task t5 = new Task(5);
        Task t6 = new Task(6);


        executor.execute(t1);
        executor.execute(t2);
        executor.execute(t3);
        executor.execute(t4);
        //executor.execute(t5);
        System.out.println("队列大小:"+queue.size());
        executor.shutdown();
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Calendar.getInstance().get(Calendar.SECOND));

        }

    }

}

休眠2秒模拟任务执行耗时

package threadpool;

public class Task implements Runnable {
    private Integer id;

    public Task(Integer id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Task [id=" + id + "]";
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(2* 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("run taskId " + id);

    }
}

这里写图片描述

先创建一个线程执行任务1,任务234加入等待队列,等待线程空闲后执行。

接下来将注释的去掉

        executor.execute(t1);
        executor.execute(t2);
        executor.execute(t3);
        executor.execute(t4);
        executor.execute(t5);

这里写图片描述

在等待队列已满的情,并且任务数量没有大于maxPoolSize的情况下,直接创建两个线程。
当大于maxPoolSzie的时候会执行默认的拒绝策略。

可以看出使用有界队列的时候线程池的瓶颈是maxPoolSzie.

  • 使用无界队列(LinkedBlockingQueue)自定义线程池,当任务数量小于corePoolSize的时候会直接创建线程执行任务,当任务数量大于corePoolSize又没有空闲的线程的时候会将任务无限制的加入到等待队列,如果任务创建的速度远大于任务执行的速度无界队列会保持快速增长,直到cpu资源耗尽。此时maxPoolSize没有任何作用。

自定义线程创建

package threadpool;

import java.util.concurrent.ThreadFactory;

public class MyThread implements ThreadFactory {

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        //设置为守护线程
         t.setDaemon(true);
        System.out.println("create "+t.getName());
        return t;
    }

}

ThreadFactory 是一个接口只有newThread(Runnable r),用来创建新的线程

自定义拒绝策略

简单的模拟一下

package threadpool;

import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

public class MyRejected implements RejectedExecutionHandler{

    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        //应该记录在日志中,做一个任务调度
        System.out.println(r.toString()+"is discard");

    }

}

扩展线程池

针对以上的代码,我们很希望知道每个任务执行的状态,对线程池的运行状态进行跟踪,输出一些有助于调试的信息,例如任务的耗时。上述代码做了一个不是合适的记录,其实jdk已经为我们提供了这样的实现。

package threadpool;

import java.util.Calendar;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyThreadPool {

    public static void main(String[] args) {

        BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(3);
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, // corePoolSize
                2, // maxPoolSize
                60, TimeUnit.SECONDS, 
                queue, 
                Executors.defaultThreadFactory(), 
                new MyRejected()) {

            long start;

            @Override
            protected void beforeExecute(Thread t, Runnable r) {
                start = System.currentTimeMillis();
                System.out.println("准备执行:" + ((Task) r).getId());
            }

            @Override
            protected void afterExecute(Runnable r, Throwable t) {

                long end = System.currentTimeMillis() - start;
                System.out.println("执行完毕:" + ((Task) r).getId() + "耗时:" + end + "毫秒");

            }

            @Override
            protected void terminated() {
                System.out.println("线程池退出");
            }
        };
        for (int i = 1; i < 7; i++) {
            Task t = new Task(i);
            executor.execute(t);
        }

        System.out.println("队列大小:" + queue.size());
        executor.shutdown();
        /*
         * while (true) { try { Thread.sleep(1000); } catch
         * (InterruptedException e) { e.printStackTrace(); }
         * System.out.println(Calendar.getInstance().get(Calendar.SECOND));
         * 
         * }
         */

    }

}

这里写图片描述

优化线程池的数量

Runtime.getRuntime().availableProcessors();

在线程池中寻找堆栈

package threadpool;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TraceTheadPoolExecutor extends ThreadPoolExecutor {

    public TraceTheadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
            BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);

    }

    private Runnable wrap(final Runnable task, final Exception clientTask, String threadName) {

        return new Runnable() {

            @Override
            public void run() {
                try {
                    task.run();
                } catch (Exception e) {
                    clientTask.printStackTrace();
                    throw e;
                }

            }

        };
    }

    private Exception clientTask() {
        return new Exception("Client stack trace");
    }

    // 跟踪在哪里提交的任务
    @Override
    public void execute(Runnable command) {

        super.execute(wrap(command, clientTask(), Thread.currentThread().getName()));
    }

    @Override
    public Future<?> submit(Runnable task) {

        return super.submit(wrap(task, clientTask(), Thread.currentThread().getName()));
    }

}

自定义ThreadPoolExecutor使我们可以看见在哪里提交的任务

package threadpool;

import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TranceThreadPool {

    public static void main(String[] args) {
        ThreadPoolExecutor executor = new TraceTheadPoolExecutor(
                0,
                5, 
                0L, 
                TimeUnit.SECONDS, 
                new SynchronousQueue<Runnable>());


        for(int i=0;i<5;i++){
            MyTask t = new MyTask(100,i);
            executor.execute(t);
        }
    }

}

这里写图片描述

以上均为阅读源码和《java高并发城西设计》所做记录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值