java-并发-源码-ThreadPoolExecutor线程运行过程

再看ThreadPoolExecutor

继承关系

ThreadPoolExecutor->AbstractExecutorService->ExecutorService->Executor

Executor提供execute方法
ExecutorService提供submit方法,可以返回future

例子:

	ExecutorService executor = new ThreadPoolExecutor
					(3, 3, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5));
    for (int i = 0; i < 10; i++) {
        executor.execute(new WorkerThread("" + i));
    }
    executor.shutdown();
    while (!executor.isTerminated()) {
    }

创建三个线程的固定线程池,队列ArrayBlockingQueue长度为5
线程池始终保持3个线程不变,队列里可以保持多个任务,线程池的线程会接收任务,避免重新创建线程;
有四个线程,主线程通过execute向线程池提交任务,池线程执行任务以及调度队列;

主线程execute方法

	public void execute(Runnable command) {
	    if (command == null) throw new NullPointerException();
	    int c = ctl.get();
	    if (workerCountOf(c) < corePoolSize) {
			//如果线程池的线程数未满,则添加worker
	        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方法,一直在做两件事,如果线程池的线程数未满,则添加worker,3次之后线程池就满了,然后不断向队列中添加任务;由于offer具有调度的功能,会激活等待的线程;

主线程功能1:addWorker

线程池有运行状态,如果运行状态条件rs >= SHUTDOWN就是非运行态,就可以自行终止,ThreadPoolExecutor中有很多处类似的判断,如果执行了线程池的终止方法,线程们会在判断条件之后结束;第一个for循环是增加workers数量;第二个是创建worker,调用这个worker线程的start方法启动这个worker的线程;

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
            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;
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
			//把runnale封装成worker
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    int rs = runStateOf(ctl.get());
                    if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize) largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

池线程:worker

worker也实现runnable,创建时把自己和task封装进线程

    Worker(Runnable firstTask) {
        setState(-1);
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
    }

run方法,把worker线程本身传入runWorker方法中

    public void run() {
        runWorker(this);
    }

runWorker方法首先从worker中获取任务,然后执行,worker中的task执行完成,设置为null,然后从队列中获取task,一直循环执行,队列中没有任务的时候线程会进入waiting状态;

    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock();	//为啥先解锁?
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                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();
                    } 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);
        }
    }

这个任务运行完成,调用task = getTask()从队列中获取任务;这个时候这个线程任然在运行;

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

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

            // 线程池停止工作才会减少池线程
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
			//超出的线程结束之后恢复数量
            if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c)) return null;
                continue;
            }

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

固定线程池为例,timed=false,会调用队列的take()方法,因为传入的是ArrayBlockingQueue,代码如下

   public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
			//如果没有内容,会阻塞
            while (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
            lock.unlock();
        }
    }

在队列中,有一个ReentrantLock,以及notEmpty和notFull两个condition,在锁上有Sync这个AQS,这两个condition归属于ReentrantLock中的AQS;
可以理解为,AQS有个同步链表,notEmpty和notFull分别有一个等待链表;同步链表竞争锁,等待链表等待唤醒;唤醒之后的线程会调到同步链表中;
在ArrayBlockingQueue中,同步队列中的线程在竞争获取队列中的数据;
所以,如果有3个池线程,它们会调用lock.lockInterruptibly竞争队列锁,只有一个线程竞争进去,
获取之后会调用lock.unlock让其他的池线程获取队列的资源;
如果队列中没有内容,在whilex循环中,await会使线程处于等待状态,await之后获取竞争锁的线程会释放锁,其他线程进入,这样全部的线程都会进入await中不运行;
await的逻辑如下

    public final void await() throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
		//构建等待链表
        Node node = addConditionWaiter();
        int savedState = fullyRelease(node);
        int interruptMode = 0;
        while (!isOnSyncQueue(node)) {
            LockSupport.park(this);
            if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                break;
        }
        if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
            interruptMode = REINTERRUPT;
        if (node.nextWaiter != null) // clean up if cancelled
            unlinkCancelledWaiters();
        if (interruptMode != 0)
            reportInterruptAfterWait(interruptMode);
    }

利用addConditionWaiter构建等待链表,savedState保存占用锁的数量,然后挂起;等待被唤醒

主线程功能2:提交任务

在execute方法中,可以看到,主线程利用workQueue.offer(command)向队列中提交任务,代码如下:

  	public boolean offer(E e) {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            if (count == items.length)
                return false;
            else {
                enqueue(e);
                return true;
            }
        } finally {
            lock.unlock();
        }
    }

lock能保证多个线程向队列提交任务的并发性;如果提交满会报错;调用enqueue把提价的任务放入队列中,在ArrayBlockingQueue就是一个循环数组;然后调用notEmpty的signal
enqueue代码如下:

   private void enqueue(E x) {
        final Object[] items = this.items;
        items[putIndex] = x;
        if (++putIndex == items.length)
            putIndex = 0;
        count++;
        notEmpty.signal();
    }

signal获取等待链表的第一个线程,对它进行doSignal

    public final void signal() {
        if (!isHeldExclusively()) throw new IllegalMonitorStateException();
        Node first = firstWaiter;
        if (first != null) doSignal(first);
    }

doSignal内容如下,持续执行transferForSignal,成功一次就会退出;

   private void doSignal(Node first) {
        do {
            if ( (firstWaiter = first.nextWaiter) == null)
                lastWaiter = null;
            first.nextWaiter = null;
        } while (!transferForSignal(first) &&
                 (first = firstWaiter) != null);
    }

transferForSignal,首先调用enq,把等待队链表中的线程提交到同步链表中,然后唤醒这个线程;

 final boolean transferForSignal(Node node) {
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false;
        Node p = enq(node);
        int ws = p.waitStatus;
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread);
        return true;
    }

执行完这些,主线程运行完了;

池线程继续:

再贴一次await代码,刚刚池线程阻塞在park中,而这个线程已经被移动到了同步链表中,因此跳出这个while循环;
然后恢复锁,如果需要做些清理工作;

    while (!isOnSyncQueue(node)) {
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) unlinkCancelledWaiters();
    if (interruptMode != 0) reportInterruptAfterWait(interruptMode);

再次贴take代码,发现队列中长度不为0了,执行dequeue从队列中取任务并运行

    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0)
            notEmpty.await();
        return dequeue();
    } finally {
        lock.unlock();
    }

总结:

线程池会维持一定的线程数量
向池中提交一个任务会唤醒一个线程去执行
可以并发的提交任务

posted @ 2016-09-22 20:09  zhangshihai1232  阅读(221)  评论(0)    收藏  举报