java 线程池

来源:互联网 发布:java web面试题 编辑:程序博客网 时间:2024/06/06 01:08

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.csdn.net/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.csdn.net/zhouhl_cn/article/details/7392607

2、源码分析

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

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

//COUNT_BITS = 29private 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.csdn.net/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.csdn.net/rebirth_love/article/details/51954836
http://blog.csdn.net/pangjiuzala/article/details/49556081