A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 大山哥哥 于 2017-11-30 10:24 编辑

         Hello.av8d, 我又来了,上次的帖子给大家介绍了下线程池的一些最基本得概念,线程池得执行流程.那这次呢,咱们要接着上次得内容继续往下进行,那么,咱们今天得主题就是线程池的基本用法.
        ok,废话不多说,咱们直接进入主题:

       首先,上次已经和大家说过了,线程池其实就是对ThreadPoolExecutor的一个具体对象,那么线程池是如何操作的呢?首先,咱们要先来带着大家参考几个api.

submit
Future<?> submit(Runnable task)
提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。该 Future 的 get 方法在成功 完成时将会返回 null。
参数:task - 要提交的任务
返回:表示任务等待完成的 Future
抛出:
RejectedExecutionException - 如果任务无法安排执行 NullPointerException - 如果该任务为 null

execute
public void execute(Runnable command)
在将来某个时间执行给定任务。可以在新线程中或者在现有池线程中执行该任务。 如果无法将任务提交执行,或者因为此执行程序已关闭,或者因为已达到其容量,则该任务由当前 RejectedExecutionHandler 处理。
参数:command - 要执行的任务。
抛出: RejectedExecutionException - 如果无法接收要执行的任务,则由 RejectedExecutionHandler 决定是否抛出 RejectedExecutionException NullPointerException - 如果命令为 null

remove
public boolean remove(Runnable task)
从执行程序的内部队列中移除此任务(如果存在),从而如果尚未开始,则其不再运行。 此方法可用作取消方案的一部分。它可能无法移除在放置到内部队列之前已经转换为其他形式的任务。例如,使用 submit 输入的任务可能被转换为维护 Future 状态的形式。但是,在此情况下,purge() 方法可用于移除那些已被取消的 Future。
参数:task - 要移除的任务
返回:
如果已经移除任务,则返回 true

其实,大家只要掌握这3个api线程池就已经可以正常的使用了,包括了,添加任务和移除任务.但是,不知道大家有没有注意到,线程池在执行任务的时候,是提供了两个,方法,所以那么问题就来了,submit和execute都是执行任务,那有什么区别呢?

那么接下来,咱们重点就是关于sumbit和execute的区别


先看结论!!!
1.execute和sumbit方法返回值不同,execute的返回值为void(即对结果不做处理),sumbit的返回值为Future<?>
2.execute是一个普通方法,执行该行代码后会继续执行下一行,不会去等待结果,但是sumbit的返回值对象future对象有一个get方法.这个方法为阻塞方法(参考ServerSocket的accept方法),该方法会等到返回值以后继续执行.
3.excute方法会抛出异常,sumbit方法不会抛出异常。除非你调用Future.get().


当然光看结果肯定有点抽象,那么接下来,带着大家看个demo
[Java] 纯文本查看 复制代码

public class ThreadPoolTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(2);

        /**
         * execute(Runnable x) 没有返回值。可以执行任务,但无法判断任务是否成功完成。
         */
        // pool.execute(new RunnableTest("Task1"));

        /**
         * submit(Runnable x) 返回一个future。可以用这个future来判断任务是否成功完成。
         */

        Future future = pool.submit(new RunnableTest("Task2"));

        try {
            // 阻塞
            // start
            // 100s 50
            // end
            // 1.监听任务是否执行完成
            // 2.处理任务执行过程中抛出的相关异常
            System.out.println(System.currentTimeMillis());

            future.get();// 2s

            System.out.println(System.currentTimeMillis());

            System.out.println("任务完成");
            
        } catch (InterruptedException e) {
        } catch (ExecutionException e) {
            // 否则我们可以看看任务失败的原因是什么
            System.out.println(e.getCause().getMessage());
        }

    }

}

class RunnableTest implements Runnable {

    private String    taskName;

    public RunnableTest(final String taskName) {
        this.taskName = taskName;
    }

    @Override
    public void run() {
        System.out.println("Inside " + taskName + " begin");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("Inside " + taskName + " end");

        throw new RuntimeException("RuntimeException from inside " + taskName);
    }

}




看如上代码,如果是execute,那执行结果如何?不用看,直接把异常抛出来对吧~
那么接下来再看sumbit,其实如果我们对结果不关心的话,那么根本就不需要去执行Future.get().如果不执行,那么这个异常也就不会被抛出来,那同理,如果我执行了get方法但是在异常里不做任何处理的话那么也不会抛出任何异常.

相关代码在附件里~
ThreadPoolTest.txt (1.76 KB, 下载次数: 8)

好了,这次就先到这里,咱们下期呢,从源码角度来分析下execute和sumbit方法~~

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马