executor经常会使用到,这里主要比较一下execute和submit方法的区别。
这个两个方法最主要的区别是如果runable中的方法抛出异常,execute会终止这个线程。而submit 不会。
这里分析一下原因。
测试代码:
ExecutorService es = Executors.newCachedThreadPool(namedThreadFactory); try { es.submit(new Runnable() { @Override public void run() { System.out.println("ok"); throw new RuntimeException(); } }); } catch (Exception e) { System.out.println(e.getMessage()); } System.out.println("end");
其实两种方法提交给ThreadPoolExecutor执行的主要逻辑都是一致的,在ThreadPoolExecutor$Worker.run()中被执行,ThreadPoolExecutor$Worker是一个工作线程,每个Worker对象对应了一个线程, t会被调用start()。
private Thread addThread(Runnable firstTask) { Worker w = new Worker(firstTask); Thread t = threadFactory.newThread(w); if (t != null) { w.thread = t; workers.add(w); int nt = ++poolSize; if (nt > largestPoolSize) largestPoolSize = nt; } return t; }
ThreadPoolExecutor$Worker.run(): Runnable task = firstTask; firstTask = null; while (task != null || (task = getTask()) != null) { runTask(task); task = null; }
注意如果没有没有任务,getTask会阻塞,然后都会执行runTask。 主要区别在于task对象的不同,sumit的task对象是FutureTask,而execute是一个普通的Runable。这里可以看到如果是Runable被执行调用run会抛出异常的,线程被中断。
runTask(Runnable task): boolean ran = false; beforeExecute(thread, task); try { task.run(); ran = true; afterExecute(task, null); ++completedTasks; } catch (RuntimeException ex) { if (!ran) afterExecute(task, ex); throw ex; }
如果是FutureTask
void innerRun(): try { runner = Thread.currentThread(); if (getState() == RUNNING) innerSet(callable.call()); else releaseShared(0); } catch (Throwable ex) { innerSetException(ex); }
Thread [Action-thread-0] ThreadPoolExecutor$Worker.runTask(Runnable) line: 886 ThreadPoolExecutor$Worker.run() line: 908 [local variables unavailable] Thread.run() line: 662 Thread [Action-thread-0] FutureTask$Sync.innerRun() line: 306 [local variables unavailable] FutureTask<V>.run() line: 138 [local variables unavailable] ThreadPoolExecutor$Worker.runTask(Runnable) line: 886 ThreadPoolExecutor$Worker.run() line: 908 [local variables unavailable] Thread.run() line: 662