java多线程——线程池简单介绍和使用

线程池的优点

  • 1、线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用。
  • 2、可以根据系统的承受能力,调整线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃。

线程池类图结构:

  • Executor接口其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable command),
  • ExecutorService接口:是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法,以及可跟踪一个或多个异步任务执行状况返回Future的方法
  • AbstractExecutorService类:ExecutorService执行方法的默认实现
  • ScheduledExecutorService接口:一个可定时调度任务的接口
  • ScheduledThreadPoolExecutor:ScheduledExecutorService的实现,一个可定时调度任务的线程池
  • ThreadPoolExecutor:线程池,通过调用Executors的静态工厂方法来创建线程池并返回一个ExecutorService对象

Executors使用静态工厂方法创建的线程池,对外返回ExecutorService实例,而实际创建的对象使用的是ThreadPoolExecutor类的实例。

Executors中创建线程池的静态方法:

  • static ExecutorService  newCachedThreadPool() 创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。 
  • static ExecutorService  newCachedThreadPool(ThreadFactory threadFactory)  创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们,并在需要时使用提供的 ThreadFactory 创建新线程。 
  • static ExecutorService  newFixedThreadPool(int nThreads) 创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。 
  • static ExecutorService  newFixedThreadPool(int nThreads, ThreadFactory threadFactory)   创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程,在需要时使用提供的 ThreadFactory 创建新线程。 
  • static ExecutorService  newSingleThreadExecutor()  创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。 
  • static ExecutorService  newSingleThreadExecutor(ThreadFactory threadFactory)  创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程,并在需要时使用提供的 ThreadFactory 创建新线程。 
  • static ExecutorService  unconfigurableExecutorService(ExecutorService executor)  返回一个将所有已定义的 ExecutorService 方法委托给指定执行程序的对象,但是使用强制转换可能无法访问其他方法。         
  • static ScheduledExecutorService  newScheduledThreadPool(int corePoolSize)  创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。 
  • static ScheduledExecutorService  newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)   创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。 
  • static ScheduledExecutorService  newSingleThreadScheduledExecutor()  创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。 
  • static ScheduledExecutorService  newSingleThreadScheduledExecutor(ThreadFactory threadFactory)  创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。 
  • static ScheduledExecutorService  unconfigurableScheduledExecutorService(ScheduledExecutorService executor)  返回一个将所有已定义的 ExecutorService 方法委托给指定执行程序的对象,但是使用强制转换可能无法访问其他方法。 

以newFixedThreadPool(int nThreads)为例分析源码:

public static ExecutorService newFixedThreadPool(int nThreads) {

        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
}

方法中只是调用了ThreadPoolExecutor的一个构造方法:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
   }
 

ThreadPoolExecutor中一共有四个构造方法,其中三个都是调用this(....)构造创建实例,也就是下面的构造:

    //this(....)调用的是下面的构造方法
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

构造函数中参数解析:

  • int corePoolSize: 核心线程数,若运行的线程数小于corePoolSize,则创建新线程来执行任务。
  • int  maximumPoolSize:允许创建的最大线程数。    若corePoolSize< 运行线程数 < maximumPoolSize,则仅在队列满时创建新线程;若corePoolSize= 运行线程数 =maximumPoolSize,创建固定大小的线程池。
  • long keepAliveTime:当线程数多于corePoolSize,多出的线程空闲时间超过keepAliveTime时将被终止。
  • TimeUnit  unit:keepAliveTime参数的时间单位,微秒、毫秒、秒等
  • BlockingQueue<Runnable> workQueue:保存任务的阻塞队列,与线程池大小有关。当运行的线程数少于corePoolSize,在有新线程任务时直接创建新线程来执行任务而无需进入队列;当运行线程数 >= corePoolSize,新的线程任务会进入队列,不创建线程;当队列满时,新的线程任务进入会创建新线程。
  • ThreadFactory  threadFactory:使用ThreadFactory创建线程,默认使用deaufltThreadFactory创建线程。
  • RejectedExecutionHandler  handler:定义处理被拒绝任务的策略,使用默认ThreadPoolExecutor.AbortPolicy,任务被拒绝时将抛出RejectExecutorException。

线程池调用:

创建好线程池之后,下面要用线程池执行任务。调用线程池执行任务的方法有两类:execute 和 submit 。execute方法在线程池的超类Executor中定义,在ThreadPoolExecutor中实现;submit方法是在ExecutorService中定义,在AbstractExecutorService中实现。

executor()方法:

    /**
     * 在将来某个时候执行给定的任务。
     * 如果无法提交任务供执行,要么是因为此执行器已关闭,要么是因为其容量已达到,
     * 则由当前{@code RejectedExecutionHandler}处理该任务。 
     */
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        //如果运行线程数小于核心线程数,创建新的线程执行任务
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //线程池处于运行状态并且加入队列成功
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        //线程池不处于运行状态且加入队列失败,则创建线程(创建的是非核心线程)
        else if (!addWorker(command, false))
            //创建线程失败,则采取阻塞处理的方式
            reject(command);
    }

execute执行线程任务,主要三个步骤:

  •           活动线程小于corePoolSize的时候创建新的线程;
  •           活动线程大于corePoolSize时都是先加入到任务队列当中;
  •           任务队列满了再去启动新的线程,如果线程数达到最大值就拒绝任务。

submit方法:

AbstractExecutorService抽象类中有三个submit重载方法:

     public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }

    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

submit方法,将线程执行记过存放到Future中。

方法中涉及到Future接口、RunnableFuture接口和newTaskFor()方法:

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

这里又出现了一个类FutureTask,FutureTask是RunnableFuture的实现类,而RunnableFuture接口又是Future和Runnable的子类。

FutureTask是一个包装类,API中对FutureTask的描述:“一个可取消的异步计算。提供了启动和取消计算、查询计算是否完成以及检索计算结果的方法。只有在计算完成后才可检索结果;如果计算尚未完成,{@code get}方法将阻塞。一旦计算完成,就不能重新启动或取消计算”

关闭线程池:

关闭线程池有两个方法:shutdown()和shutdownNow()

  • shutdown方法等待提交的任务执行完成并不再接受新任务,在完成全部提交的任务后关闭
  • shutdownNow方法将强制终止所有运行中的任务并不再允许提交新任务
    /**
     * 将正在执行的任务完成,但是不会接受新的任务。任务执行完毕后关闭线程池
     *
     */
    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(SHUTDOWN);
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }

    /**
     * 尝试停止所有正在积极执行的任务,停止处理等待的任务,并返回等待执行的任务列表。
     * 从该方法返回时,将从任务队列中删除这些任务。
     */
    public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(STOP);
            interruptWorkers();
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
        return tasks;
    }

    public boolean isShutdown() {
        return ! isRunning(ctl.get());
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值