java 线程池

1、java多线程的使用

1.1 当有多个任务时:

new Thread的弊端如下:
a. 每次new Thread新建对象性能差。
b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
c. 缺乏更多功能,如定时执行、定期执行、线程中断。
相比new Thread,Java提供的四种线程池的好处在于:
a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
c. 提供定时执行、定期执行、单线程、并发数控制等功能。

1.2 线程池的种类

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

提交任务时 exucute只接收Runnable接口,且没返回值
submit可以接收Runnable和Callable且有返回值。也可以捕获线程的异常,做相应的处理。execute无法在外部捕获异常
http://blog.youkuaiyun.com/yuzhiboyi/article/details/7775266

1.3 定制线程池
/**
* @param corePoolSize 核心线程数
核心线程会一直存活,及时没有任务需要执行
当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理
设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭
* @param maximumPoolSize 任务队列容量(阻塞队列)
当核心线程数达到最大时,新任务会放在队列中排队等待执行
* @param keepAliveTime  线程空闲时间
当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
如果allowCoreThreadTimeout=true,则会直到线程数量=0
* @param unit 时间单位
* @param workQueue 任务队列容量(阻塞队列)
当核心线程数达到最大时,新任务会放在队列中排队等待执行
* @param threadFactory  创建新线程时使用
是构造Thread的方法,你可以自己去包装和传递,主要实现newThread方法即可;
* @param handler 拒绝策略
* @throws IllegalArgumentException if one of the following holds
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue} is null
     */
ThreadPoolExecutor(int corePoolSize,
                  int maximumPoolSize,
                  long keepAliveTime,
                  TimeUnit unit,
                  BlockingQueue<Runnable> workQueue
                  hreadFactory threadFactory,
                  RejectedExecutionHandler handler
                  )

workQueue的选择:
1.直接提交,默认使用SynchronousQueue。SynchronousQueue收到一个任务,直接提交给线程。如果没有线程可以执行新任务则执行拒绝策略
2.无界队列,如LinkedBlockingQueue,当任务数量达到核心线程数,再添加新任务会缓存,而不会触发maximumPoolSize。当缓存的任务数量过多时,可能导致资源耗尽
3.有界队列,如ArrayBlockingQueue,可以防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。

corePoolSize的选择:
http://blog.youkuaiyun.com/zhouhl_cn/article/details/7392607

2、源码分析

先看懂线程池的几个状态,在读源码会好很多

线程池有几个运行状态 定义在

//COUNT_BITS = 29
private static final int RUNNING    = -1 << COUNT_BITS;//1110...
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;//110...

1 当创建线程池后,初始时,线程池处于RUNNING状态;
2 如果调用了shutdown()方法,则线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕;
3 如果调用了shutdownNow()方法,则线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务;
4 当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态。

ExecutorService cache = Executors.newCachedThreadPool();
        Future future = cache.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
               return null;
            }
        });

AbstractExecutorService继承ExecutorService并实现submit方法

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

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }

主要将task封装成FutureTask,然后调用Executor的execute方法。
具体的execute方法由AbstractExecutorService的子类ThreadPoolExecutor完成

public void execute(Runnable command) {
        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)
                //如果总线程数为0 会启动一个空线程
                addWorker(null, false);
        }
        //尝试启动薪线程执行任务。如果失败,则表示线程池关闭或队列满,执行拒绝策略
        else if (!addWorker(command, false))
            reject(command);
    }

execute的操作主要是调用addWorker执行任务

private boolean addWorker(Runnable firstTask, boolean core) {
    //如果当前线程数没有超过corePoolSize或maximumPoolSize(由core控制),则调用compareAndIncrementWorkerCount将线程数+1
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
//
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            //将runnable封装为Worker,在Worker中会创建一个线程
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        //将Work加入workers,它是一个hashset
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                //如果添加成功 启动Worker的线程
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

addWorker将任务包装成Worker,并调用start()方法启动一个线程

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
    /** Thread this worker is running in.  Null if factory fails. */
        final Thread thread;
        /** Initial task to run.  Possibly null. */
        Runnable firstTask;
        /** Per-thread task counter */

        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        /** Delegates main run loop to outer runWorker  */
        public void run() {
            runWorker(this);
        }
}

Worker的构造方法中会调用getThreadFactory()获取一个薪线程,然后调用runWorker方法。

final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock();//加锁
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                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;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            //线程多于任务数时,是否结束线程标记
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                //线程数-1 并返回null结束本线程
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
                //timed为true表示当前线程大于核心线程数,或者allowCoreThreadTimeOut为true,作用是如果没有足够的任务,将结束多余的线程
                Runnable r = timed ?
                    //设置超时,如果没有任务,将会被结束
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    //如果没有任务,会一直阻塞,直到有任务为止
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

是否能返回任务,与 timed有很大关系

private void processWorkerExit(Worker w, boolean completedAbruptly) {
        //如果因为线程异常退出 线程数直接-1
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks;
            //移除worker,即一个线程
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }

        //尝试终止线程池
        tryTerminate();

        int c = ctl.get();
        //比STOP小的只有SHUTDOWN
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false);
        }
    }
final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            if (workerCountOf(c) != 0) { // Eligible to terminate
                //中断线程
                interruptIdleWorkers(ONLY_ONE);
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();
                    } finally {
                        ctl.set(ctlOf(TERMINATED, 0));
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

总结:
1、当可以新建线程时
通过Worker包装新Runnable并启动一个线程,并通过线程的run调用Worker的runWorker方法,并执行真正的任务。如果当前任务执行完,会执行阻塞队列中的任务。
2、如果不需要继续新建线程,则将任务放入阻塞队列。

这里写图片描述
整体框架是一个命令模式
Executor为抽象命令类,声明了一个execute接口
ThreadPoolExecutor为具体命令类,实现execute,执行接收者的具体方法
Runnable为接收者,做具体操作
只需要实现Runnable,封装性好,调用方便
每一个任务实现一个Runnable 扩展性好
http://blog.youkuaiyun.com/with_dream/article/details/77480805

2.2 拒绝策略

调用execute(Runnable command)添加任务时,如果队列满,会执行拒绝策略

public interface RejectedExecutionHandler {
    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

主要有:
AbortPolicy() 抛异常
CallerRunsPolicy() 交由调用者线程处理
DiscardOldestPolicy() 抛弃最老的任务
DiscardPolicy() 不接受新任务

参考:
http://blog.youkuaiyun.com/rebirth_love/article/details/51954836
http://blog.youkuaiyun.com/pangjiuzala/article/details/49556081

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值