java 线程池使用和详解

线程池的使用

构造方法javascript

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
  • corePoolSize:线程池维护线程的最少数量
  • maximumPoolSize:线程池维护线程的最大数量
  • keepAliveTime:线程池维护线程所容许的空闲时间
  • unit:线程池维护线程所信息的空闲时间的单位
  • workQueue:线程池所使用的缓冲队列
  • threadFactory:线程建立工厂类
  • handler:线程池对任务的处理策略

注意

  • 线程池在建立的时候是不建立线程的,只有加入任务才建立线程,固然能够调用prestartCoreThread方法(是在ThreadPoolExecutor类中实现的)来初始化一个线程。
  • 线程池先会建立完corePoolSize个线程,在把任务保存到队列中,队列满后才会再建立线程,直到规定的maximumPoolSize,而后会执行拒绝策略。
  • 设置线程池的大小参考
    • 若是是CPU密集型任务,就须要尽可能压榨CPU,参考值能够设为 NCPU+1
    • 若是是IO密集型任务,参考值能够设置为2*NCPU

BlockingQueue经常使用的3个实现类java

  1. ArrayBlockingQueue 构造参数必须带一个int参数来指明其大小,FIFO
  2. LinkedBlockingQuene 大小不定,能够人为指定,若没有有Integer.MAX_VALUE来决定。FIFO
  3. SynchronousQueue 对其操做必须放和取交替完成。在线程池中它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务

LinkedBlockingQueue的数据吞吐量要大于ArrayBlockingQueue,但在线程数量很大时其性能的可预见性低于ArrayBlockingQueue. SynchronousQueue初始化后必须先有其余线程对其使用take()方法后才能使用put() 或者 offer()方法微信

java 定义好的4中类型的线程池

  1. newCachedThreadPool建立一个可缓冲线程池,若是线程池长度超过处理须要,可灵活回收空闲线程,若无可用线程,则新建线程
  2. newFixedThreadPool建立一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  3. newScheduledThreadPool 建立一个定长线程池,支持定时和周期性任务执行。
  4. newSingleThreadExecutor 一个单线程化的线程池,确保全部任务按照指定的顺序执行。

下面是线程池核心的执行代码,只看懂一点:cry:并发

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        //它在执行完一个线程会getTask再去取一个,直到没有任务。
        while (task != null || (task = getTask()) != null) {
            w.lock();
            //.......删除N行代码
            try {
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    task.run();
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

gettask方法性能

private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            //......省略N行代码

            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

这里用到了BlockingQueue的方法,很巧妙的使用。timed是判断这个线程是否能够回收,由咱们设置的allowCoreThreadTimeOut和当前线程池线程大小决定的。当要回收,用的是poll方法,不能回收用的是take方法阻塞线程线程

线程池的shutdown()和shutdownNow();

  • shutdown()方法会更改线程池的状态为SHUTDOWN状态,并不会当即终止。此时不能往线程池中添加任务,不然会抛出RejectedExecutionException异常。它会等线程池里的全部任务都处理完毕再退出线程。
  • shutdownNow()方法会当即更改状态为STOP状态。并试图中止全部正在执行的线程,再也不处理还在池队列中等待的任务,它会返回那些未执行的任务。其试图终止线程的方法是经过调用Thread.interrupt()方法来实现的。

提个问题,线程池有两种提交方式execute()和submit()区别,能够在评论区讨论哦!请关注微信公众号,查看,嘻嘻。不过之后会在评论区回复的!!rest


欢迎关注个人微信公众号cobs-snail,让咱们一块儿前进吧!!code

前进吧蜗牛

相关文章
相关标签/搜索