Java多线程-线程池

线程池

以下整理自 http://www.cnblogs.com/dolphin0520/p/3932921.html (万分感谢)

1.ThreadPoolExecutor类

ava.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类
,因此如果要透彻地了解Java中的线程池,必须先了解这个类。
下面我们来看一下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) {
       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) {
    ...
   }
几个构造器都有如下参数
  • corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。
    在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行
    任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的
    名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一
    个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个
    线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;

  • maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最
    多能创建多少个线程;

  • keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中
    的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于
    corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到
    keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了
    allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,
    keepAliveTime参数也会起作用,直到线程池中的线程数为0;

  • workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:

  • ArrayBlockingQueue;

  • LinkedBlockingQueue;

  • SynchronousQueue;

ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。

  • 对于corePool,ThreadPoll,BlockingQueue的关系,如下图
    在这里插入图片描述
  • unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒
  • threadFactory:线程工厂,主要用来创建线程;
  • handler:表示当拒绝处理任务时的策略,有以下四种取值:
  • ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  • ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
  • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
  • ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

2.继承关系

在这里插入图片描述

  • AbstractExecutorService
public abstract class AbstractExecutorService implements ExecutorService {
   protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { };
   protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { };
   public Future<?> submit(Runnable task) {};
   public <T> Future<T> submit(Runnable task, T result) { };
   public <T> Future<T> submit(Callable<T> task) { };
   private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
                           boolean timed, long nanos)
       throws InterruptedException, ExecutionException, TimeoutException {
   };
   public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
       throws InterruptedException, ExecutionException {
   };
   public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                          long timeout, TimeUnit unit)
       throws InterruptedException, ExecutionException, TimeoutException {
   };
   public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
       throws InterruptedException {
   };
   public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                        long timeout, TimeUnit unit)
       throws InterruptedException {
   };
}

ExecutorService接口:

public interface ExecutorService extends Executor {

    void shutdown();
    boolean isShutdown();
    boolean isTerminated();
    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;
    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

Excutior接口

public interface Executor {
    void execute(Runnable command);
}
  • Executor是一个顶层接口,在它里面只声明了一个方法execute(Runnable),返回值为void,参数为Runnable类型,从字面意思可以理解,就是用来执行传进去的任务的;

  • 然后ExecutorService接口继承了Executor接口,并声明了一些方法:submit、invokeAll、invokeAny以及shutDown等;

  • 抽象类AbstractExecutorService实现了ExecutorService接口,基本实现了ExecutorService中声明的所有方法;

  • 然后ThreadPoolExecutor继承了类AbstractExecutorService。

3.在ThreadPoolExecutor类中有几个非常重要的方法

execute()
submit()
shutdown()
shutdownNow()
  • execute()方法实际上是Executor中声明的方法,在ThreadPoolExecutor进行了具体的实现,
    这个方法是ThreadPoolExecutor的核心方法,通过这个方法可以向线程池提交一个任务,
    交由线程池去执行。

  • submit()方法是在ExecutorService中声明的方法,在AbstractExecutorService就已经有了
    具体的实现,在ThreadPoolExecutor中并没有对其进行重写,这个方法也是用来向线程池提交任
    务的,但是它和execute()方法不同,它能够返回任务执行的结果,去看submit()方法的实现,
    会发现它实际上还是调用的execute()方法,只不过它利用了Future来获取任务执行结果

  • shutdown()和shutdownNow()是用来关闭线程池的

4、使用示例(以下代码根据原博主改编了一下,能动态获取线程池的数据)

package xyh;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author XiangYida
 * @version 2019/3/4 19:36
 */
public class Test {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 15, 200, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(12));
        System.out.println("                         核心池的数量" + executor.getCorePoolSize() + " 线程池中线程数目:" + executor.getPoolSize() + ",队列中等待执行的任务数目:" +
                executor.getQueue().size() + ",已执行完别的任务数目:" + executor.getCompletedTaskCount());
        for (int i = 0; i < 15; i++) {
            MyTask myTask = new MyTask(i);
            executor.execute(myTask);
        }
        Get g = new Get(executor);
        new Thread(g).start();
        executor.shutdown();
    }
}

class MyTask implements Runnable {
    private int taskNum;

    public MyTask(int num) {
        this.taskNum = num;
    }

    @Override
    public void run() {
        System.out.println("正在执行task " + taskNum);
        try {
            Thread.currentThread().sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task " + taskNum + "执行完毕");
    }
}

class Get implements Runnable {
    ThreadPoolExecutor executor;

    public Get(ThreadPoolExecutor executor) {
        this.executor = executor;
    }

    @Override
    public void run() {
        while (executor.getPoolSize() != 0) {
            System.out.println("                         核心池的数量" + executor.getCorePoolSize() + " 线程池中线程数目:" + executor.getPoolSize() + ",队列中等待执行的任务数目:" +
                    executor.getQueue().size() + ",已执行玩别的任务数目:" + executor.getCompletedTaskCount());
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("                         核心池的数量" + executor.getCorePoolSize() + " 线程池中线程数目:" + executor.getPoolSize() + ",队列中等待执行的任务数目:" +
                executor.getQueue().size() + ",已执行完别的任务数目:" + executor.getCompletedTaskCount());
    }
}
实验结果
---------------------------核心池的数量3 线程池中线程数目:0,队列中等待执行的任务数目:0,已执行完别的任务数目:0
正在执行task 0
正在执行task 1
正在执行task 2
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:12,已执行玩别的任务数目:0
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:12,已执行玩别的任务数目:0
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:12,已执行玩别的任务数目:0
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:12,已执行玩别的任务数目:0
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:12,已执行玩别的任务数目:0
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:12,已执行玩别的任务数目:0
task 0执行完毕
正在执行task 3
task 1执行完毕
task 2执行完毕
正在执行task 4
正在执行task 5
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:9,已执行玩别的任务数目:3
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:9,已执行玩别的任务数目:3
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:9,已执行玩别的任务数目:3
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:9,已执行玩别的任务数目:3
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:9,已执行玩别的任务数目:3
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:9,已执行玩别的任务数目:3
task 3执行完毕
正在执行task 6
task 4执行完毕
task 5执行完毕
正在执行task 7
正在执行task 8
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:6,已执行玩别的任务数目:6
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:6,已执行玩别的任务数目:6
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:6,已执行玩别的任务数目:6
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:6,已执行玩别的任务数目:6
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:6,已执行玩别的任务数目:6
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:6,已执行玩别的任务数目:6
task 6执行完毕
正在执行task 9
task 7执行完毕
task 8执行完毕
正在执行task 10
正在执行task 11
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:3,已执行玩别的任务数目:9
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:3,已执行玩别的任务数目:9
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:3,已执行玩别的任务数目:9
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:3,已执行玩别的任务数目:9
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:3,已执行玩别的任务数目:9
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:3,已执行玩别的任务数目:9
task 9执行完毕
正在执行task 12
task 10执行完毕
task 11执行完毕
正在执行task 13
正在执行task 14
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:12
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:12
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:12
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:12
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:12
---------------------------核心池的数量3 线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:12
task 12执行完毕
task 14执行完毕
task 13执行完毕
---------------------------核心池的数量3 线程池中线程数目:0,队列中等待执行的任务数目:0,已执行完别的任务数目:15

参考博客
https://www.cnblogs.com/dolphin0520/p/3932921.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java多线程编程中,配置线程池的参数是非常重要的。根据不同的业务需求,可以设置线程池的参数来控制线程的数量和行为。根据引用中的例子,可以使用`Executors.newFixedThreadPool(int nThreads)`来创建一个固定线程数量的线程池。在这个方法中,`nThreads`参数表示线程池中的线程数量,只有这个数量的线程会被创建。然后,可以使用`pool.execute(Runnable command)`方法来提交任务给线程池执行。 在配置线程池时,需要考虑业务的性质。如果是CPU密集型的任务,比如加密、计算hash等,最佳线程数一般为CPU核心数的1-2倍。而如果是IO密集型的任务,比如读写数据库、文件、网络读写等,最佳线程数一般会大于CPU核心数很多倍。这样可以充分利用IO等待时间来执行其他任务,提高程序的性能。引用中给出了一些常见的线程池特点和构造方法参数。 总之,根据业务需求和特点,合理配置线程池的参数可以提高程序的性能和效率。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java多线程线程池的参数和配置](https://blog.csdn.net/MRZHQ/article/details/129107342)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Java多线程线程池(合理分配资源)](https://blog.csdn.net/m0_52861000/article/details/126869155)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Java多线程线程池](https://blog.csdn.net/weixin_53611788/article/details/129602719)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值