Java多线程深入学习-2.ThreadPoolExecutor线程池源码深入解析-提交任务与线程复用

1.submit与execute方法的区别

//ExecutorService中定义
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);

//Executor中定义
    void execute(Runnable command);


//AbstractExecutorService中实现
    /**
     * 提交任务 -Runnable
     */
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();	//校验
        RunnableFuture<Void> ftask = newTaskFor(task, null);//创建Future
        execute(ftask);	//调用execute方法	这里未实现
        return ftask;	//返回当前Future
    }
    /**
     * 提交任务 -Runnable result
     */
    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();//校验
        RunnableFuture<T> ftask = newTaskFor(task, result);//创建Future
        execute(ftask);	//调用execute方法	这里未实现
        return ftask;	//返回当前Future
    }
    /**
     * 提交任务 -Callable
     */
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();	//校验
        RunnableFuture<T> ftask = newTaskFor(task);			//创建Future
        execute(ftask);	//调用execute方法	这里未实现
        return ftask;	//返回当前Future
    }

从接口定义来看,execute只能提交Runnable类型的任务,而且任务提交无返回值。而submit可以提交Runnable或者Callable类型的任务,而且会返回一个Future结果,submit方法会把提交的任务封装到一个RunnableFuture中然后调用execute方法提交任务。

1.1submit方法中Runnable任务是如何被封装成RunnableFuture的

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

    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW; 
    }

    public static Callable<Object> callable(final PrivilegedExceptionAction<?> action) {
        if (action == null)
            throw new NullPointerException();
        return new Callable<Object>() {
            public Object call() throws Exception { return action.run(); }};
    }

看代码可知,是将新建一个Callable实现call方法的代码就是直接调用Runnable的run方法实现,之后再将Callable封装到FutureTask中

2.线程的重复使用?

一般线程开启后执行run方法,run方法执行结束后线程就关闭了,那么ThreadPoolExecutor是怎么让线程重复使用的呢?

    private boolean addWorker(Runnable firstTask, boolean core) {
        //省略代码-----
            w = new Worker(firstTask);
            final Thread t = w.thread;
        //省略代码-----
    }

从代码中可知,线程池添加新线程的时候时从Worker中拿的,而Worker创建的时候接收了我们提交的任务,让我们看一下Worker时怎么创建的吧

    private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable {
        private static final long serialVersionUID = 6138294804551838833L;

        final Thread thread;
        Runnable firstTask;
        volatile long completedTasks;
        
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        //Worker的run方法调用的是ThreadPoolExecutor的runWorker方法
        public void run() {
            runWorker(this);
        }
        //-----------
    }

观察代码,可知Worker继承了AbstractQueuedSynchronizer和Runnable,内部还定义了Thread和Runnable两个属性,在初始化的时候会接收任务到Runnable中,然后从线程工厂中获取到一个线程,并将自身对象赋值给线程,再将线程赋值到自己的Thread属性中。

豆豆:这关系真乱

理一下,也就是worker.thread.start()线程开启之后,会调用worker对象中的run方法。也就是会开启一个线程,去执行runWorker(worker)方法,Worker类时ThreadPoolExecutor的一个内部类,调用的runWorker方法其实是在ThreadPoolExecutor中定义的。

    /**
     * 线程执行
     */
    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread(); //当前线程
        //取出需要执行的任务
        Runnable task = w.firstTask;
        w.firstTask = null;	//取出之后将firstTask置空
        w.unlock();	//豆豆:不管咋说,先unlock一下
        boolean completedAbruptly = true;
        try {
        	//如果task不是null,或者去队列中取任务,注意这里会阻塞
            while (task != null || (task = getTask()) != null) {
            	//这个lock在这里是为了如果线程被中断,那么会抛出InterruptedException,而退出循环,结束线程
            	w.lock();
            	//判断线程是否需要中断
                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();	//执行任务的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 {
        	//Worker退出
            processWorkerExit(w, completedAbruptly);
        }
    }

    private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // 若为false则执行成功 否则则是发生了异常
            decrementWorkerCount();	//发生异常,执行被中断设置ctl值为-1	若无异常不执行

        final ReentrantLock mainLock = this.mainLock;	//获取锁
        mainLock.lock();	//加锁
        try {
            completedTaskCount += w.completedTasks;
            workers.remove(w);	//移除任务w
        } finally {
            mainLock.unlock();	//解锁
        }

        tryTerminate();

        int c = ctl.get();
        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 --- 递归了------
            addWorker(null, false);
        }
    }

原来这里会重复调用addWorker,一直去工作,不过当没有任务的时候调用getTask会阻塞线程看一下getTask代码吧

    private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            //检查线程池的状态,如果已经是STOP及以上的状态,或者已经SHUTDOWN,队列也是空的时候,直接return null,并将Worker数量-1
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // 注意这里的allowCoreThreadTimeOut参数,字面意思是否允许核心线程超时,即如果我们设置为false,那么只有当线程数wc大于corePoolSize的时候才会超时
            //更直接的意思就是,如果设置allowCoreThreadTimeOut为false,那么线程池在达到corePoolSize个工作线程之前,不会让闲置的工作线程退出
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
            //确认超时,将Worker数-1,然后返回
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
            	//从队列中取任务,根据timed选择是有时间期限的等待还是无时间期限的等待
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/luo_mu_hpu/article/details/107937666