多线程学习笔记:3.使用线程池技术实现多线程二。

ThreadPoolExecutor:之前创建的各种线程池,实际都是通过调用该类的构造方法创建的。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

各参数的意义:

  • corePoolSize:线程池的核心线程数,当核心线程数被创健后,即使没有任务执行了,默认也会存活。当allowCoreThreadTimeOut为true,核心线程也会被回收。
  • maximumPoolSize:线程池允许的最大线程数。除去核心线程,其他的就是非核心线程,他们会在需要时创建,空闲时间超过keepAliveTime后会被回收。
  • keepAliveTime: 指的是空闲线程结束的超时时间;
  • unit :是一个枚举,表示 keepAliveTime 的单位;
  • workQueue:表示存放任务的BlockingQueue<Runnable队列。
  • BlockingQueue:阻塞队列(BlockingQueue)是java.util.concurrent下的主要用来控制线程同步的工具。如果BlockQueue是空的,从BlockingQueue取东西的操作将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤醒。同样,如果BlockingQueue是满的,任何试图往里存东西的操作也会被阻断进入等待状态,直到BlockingQueue里有空间才会被唤醒继续操作。
  • threadFactory:线程工厂类,当不指定时,会使用默认工厂类。可以自定义一个线程工厂类,在newThread方法中对线程的一些属性进行自定义设置。
public interface ThreadFactory {

    Thread newThread(Runnable r);
}
  • handler 拒绝策略,当线程数已最大,队列也满了的时候,用来处理新的任务。可自定义。
    public interface RejectedExecutionHandler {
    
        void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
    }

    ThreadPoolExecutor已实现了四种拒绝策略:

  • AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满。默认拒绝策略

 public static class AbortPolicy implements RejectedExecutionHandler {    
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }
  • DisCardPolicy:不执行新任务,也不抛出异常
 public static class DiscardPolicy implements RejectedExecutionHandler {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }
  • DisCardOldSetPolicy:将消息队列中的第一个任务删除,然后重新提交当前任务。
     public static class DiscardOldestPolicy implements RejectedExecutionHandler {
            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                if (!e.isShutdown()) {
                    e.getQueue().poll();
                    e.execute(r);
                }
            }
        }
  •  CallerRunsPolicy:直接调用execute来执行当前任务。这个策略不想放弃任务,直接该execute的线程本身来执行。
     public static class CallerRunsPolicy implements RejectedExecutionHandler {
            public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                if (!e.isShutdown()) {
                    r.run();
                }
            }
        }
    线程池的执行过程:

  • 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
  • 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;
  • 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;
  • 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么执行拒绝策略。

所以我们也可以根据需要自定义线程池。

public class MyPool {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2,4,1000,
                TimeUnit.MILLISECONDS, new ArrayBlockingQueue(3),
                new MyThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());
        ArrayList<MyRun> myRuns = new ArrayList<>();
        //任务10大于4+3=7
        for (int i = 0; i < 10; i++) {
            MyRun run = new MyRun();
            myRuns.add(run);
        }
        for (MyRun myRun : myRuns) {
            executor.execute(myRun);
        }
    }
}
class MyThreadFactory implements ThreadFactory{

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        return t;
    }
}
class MyRun implements Runnable{
    private static int num = 0;
    //保证创建的每个MyRun都有不同的id
    private final int id =num++;
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"   "+id);
    }
}

输出结果:

这里使用的是第四种拒绝策略,为了不放弃任务,调用了主线程执行任务。也可以设置其他策略查看效果。

猜你喜欢

转载自blog.csdn.net/qq_42283110/article/details/86617381