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

来源:互联网 发布:如何招聘php程序员 编辑:程序博客网 时间:2024/06/05 22:36

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

     




     









FutureTask  继承 RunnableFuture , RunnableFuture 实现接口 Runnable


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

     

ExecutorService es = Executors.newFixedThreadPool(15);es.submit(new Callable<String>(){@Overridepublic 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<Runnable>(),                                      threadFactory);    }

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

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

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

    

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {        return new FutureTask<T>(runnable, value);    }    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {        return new FutureTask<T>(callable);    }    public Future<?> submit(Runnable task) {        if (task == null) throw new NullPointerException();        RunnableFuture<Void> ftask = newTaskFor(task, null);        execute(ftask);        return ftask;    }    public <T> Future<T> submit(Runnable task, T result) {        if (task == null) throw new NullPointerException();        RunnableFuture<T> ftask = newTaskFor(task, result);        execute(ftask);        return ftask;    }    public <T> Future<T> submit(Callable<T> task) {        if (task == null) throw new NullPointerException();        RunnableFuture<T> ftask = newTaskFor(task);        execute(ftask);        return ftask;    }

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

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

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

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

   

static final class RunnableAdapter<T> implements Callable<T> {        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<T>通过父类RunnableFuture也是实现了Runnable接口的 ,  所以执行也是start方法 。 run源码

public void run() {        if (state != NEW ||            !UNSAFE.compareAndSwapObject(this, runnerOffset,                                         null, Thread.currentThread()))            return;        try {            Callable<V> 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()是如何实现的 ,具体后续分析

  <span style="color:#000000;"> 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);    }</span>


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

逻辑图


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

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

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

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

























0 0
原创粉丝点击