线程学习二:线程池执行Runnable与Callable

1、了解线程池几个类之间的关系 (结合图看后面的分析)

      线程学习二:线程池执行Runnable与Callable_第1张图片




     









FutureTask  继承 RunnableFuture , RunnableFuture 实现接口 Runnable


2、分析常用调用线程池代码(以下称为代码A

     

ExecutorService es = Executors.newFixedThreadPool(15);
		es.submit(new Callable(){

			@Override
			public String call() throws Exception {
				return null;
			}});
		es.submit(new myThread());

1)首先我们看看Executors.newFixedThreadPool()这个方法的源码

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue(),
                                      threadFactory);
    }

  可以看到,它实际返回的是ThreadPoolExecutor对象es

2)再看看es.submit()这个方法是如何实现的

      在源码中,我们会发现ThreadPoolExecutor并没有方法submit,它是调用了父类abstractExecutorService.submit()方法,源码如下

    

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

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


    public Future submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

    public  Future submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }

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

可以看到, abstractExecutorService是把Callable 对象和 Runnable对象转换为了RunnbaleFuture的实现类 FutureTask,然后调用execute()方法。

而ThreadPoolExecutor类中是重写了execute()方法的,所以代码A中的es.submit实际上执行的是ThreadPoolExecutor.executor().

3)了解Callable 与 Runnable转换为FutureTask   (这里不截源码了) 与 FutureTask的run方法。

      FutureTask中有个Callable属性,如果是Callable转,那么直接赋值就好了,如果是Runnable转,那么Eexcutors中有个类RunnableAdapter,将Runnable对象赋值给一个RunnableAdapter对象ra,然后把ra赋值给FutureTask中的Callable属性就好了。

   

static final class RunnableAdapter implements Callable {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }
FutureTask通过父类RunnableFuture也是实现了Runnable接口的 ,  所以执行也是start方法 。 run源码

public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }
结果还是把Callable的call()方法丢到了Runnable的run()方法中 ,

看到里面的set(result)没有,就是通过一个全局变量,变相的返回线程执行结果,获取是FutureTask.get()方法。


  


4)再看看ThreadPoolExecutor.executor()是如何实现的 ,具体后续分析

   public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        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)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }


上面的addWorker(COMMAND,FLAG)方法中,满足条件会构建new Thread(FutureTask) t,调用t.start();

逻辑图

线程学习二:线程池执行Runnable与Callable_第2张图片

5)终于到最后了,可以说我最想说的话了 。

    之前没看代码,狗日的以为Callable是个很神奇的东西,就是Thread的兄弟,使用起来也挺神秘,只见过再ExecutorService.submit()见到过 。

现在才知道,Callable仅仅只是为线程执行的时候能够返回对象,且仅仅只能在ExecutorService.submit()中使用,其他无卵用。

绕来绕去还是Thread与Runnable的start方法与run方法啊。

























你可能感兴趣的:(java_线程,线程池,线程,Callable,ExecutorService)