在線程池里提交任務經常見到submit與execute,如何選擇,傻傻分不清楚。那么他們倆有什么區別,使用場景是什么?這篇博客將會介紹。
1.方法定義
void execute(Runnable command); Future<T> submit(Callable<T> task); Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task);
2.使用上的區別
2.1execute沒有返回值(Future)
2.2執行結果(future.get)
2.3submit可以捕獲runnable里的異常
3.示例
3.1使用Future判斷任務是否執行完,5s后任務超時就停止任務。
public class ThreadPoolSubmitFuture { static class MyRunnable implements Runnable { private String jobName; private Thread nowThread; MyRunnable(String jobName) { this.jobName = jobName; } public void setInterrupted() { nowThread.interrupt(); } @Override public void run() { nowThread = Thread.currentThread(); try { while (true) { Thread.sleep(1000); // 寫了sleep就不用再判斷isInterrupted()了 System.err.println("當前線程:" + Thread.currentThread().getName() + " 當前任務:" + jobName); } } catch (InterruptedException e) { System.err.println("當前線程:" + Thread.currentThread().getName() + " 當前任務:" + jobName + "馬上停止"); e.printStackTrace(); } } } public static void main(String[] args) throws InterruptedException { ExecutorService es = Executors.newFixedThreadPool(2, new MyThreadFactory()); MyRunnable job1 = new MyRunnable("job-1"); Future<?> f = es.submit(job1); try { f.get(5, TimeUnit.SECONDS); } catch (ExecutionException e) { e.printStackTrace(); } catch (TimeoutException e) { // 超時停止 job1.setInterrupted(); e.printStackTrace(); } try { f.get(); } catch (ExecutionException e) { e.printStackTrace(); } } }
3.2執行結果
MyRunnable不變
public static void main(String[] args) throws InterruptedException { ExecutorService es = Executors.newFixedThreadPool(2, new MyThreadFactory()); MyRunnable job1 = new MyRunnable("job-1"); Future<String> f = es.submit(job1, "我執行完了"); try { f.get(5, TimeUnit.SECONDS); } catch (ExecutionException e) { e.printStackTrace(); } catch (TimeoutException e) { // 超時停止 job1.setInterrupted(); e.printStackTrace(); } try { String rs = f.get(); System.err.println("job-1執行完后,說了啥:" + rs); } catch (ExecutionException e) { e.printStackTrace(); } }
3.3捕獲異常
在Runnale中可以拋出RuntimeException,不可以拋出Exception
public class ThreadPoolSubmitFutureException { static class MyRunnable implements Runnable { private String jobName; private Thread nowThread; MyRunnable(String jobName) { this.jobName = jobName; } public void setInterrupted() { nowThread.interrupt(); } @Override public void run() { nowThread = Thread.currentThread(); try { while (true) { Thread.sleep(1000); // 寫了sleep就不用再判斷isInterrupted()了 System.err.println("當前線程:" + Thread.currentThread().getName() + " 當前任務:" + jobName); } } catch (InterruptedException e) { System.err.println("當前線程:" + Thread.currentThread().getName() + " 當前任務:" + jobName + "馬上停止"); e.printStackTrace(); throw new RuntimeException("當前線程:" + Thread.currentThread().getName() + " 當前任務:" + jobName + " 我出現異常了"); } } } public static void main(String[] args) throws InterruptedException { ExecutorService es = Executors.newFixedThreadPool(2, new MyThreadFactory()); MyRunnable job1 = new MyRunnable("job-1"); Future<?> f = es.submit(job1); try { f.get(5, TimeUnit.SECONDS); } catch (ExecutionException e) { e.printStackTrace(); } catch (TimeoutException e) { // 超時停止 job1.setInterrupted(); e.printStackTrace(); } try { f.get(); } catch (ExecutionException e) { e.printStackTrace(); } catch (RuntimeException re) { re.printStackTrace(); } } }
3.4異常不捕獲會怎么樣
execute會導致執行的線程銷毀,線程池會重新創建一個新的線程來執行其他任務,這樣就會導致線程池的線程得不到復用。
submit不會導致執行的線程銷毀,但是你不future.get()你永遠不會知道這個異常。
4.總結
4.1如果任務有返回值,有拋出異常,使用submit
4.2如果要判斷任務執行完,以便進行其他處理,使用submit
4.3使用submit拋出的異常,不捕獲將不會知道有這個異常