1. 程式人生 > >java多執行緒:ExecutorService解析(五)

java多執行緒:ExecutorService解析(五)

       前面幾篇部落格寫到的多執行緒實現基本都是顯式呼叫了Thread的start()方法,除了這種方法有沒有其他的實現方法呢,這裡我們來看下java.util.concurrent包下的ExecutorService實現。

看一個簡單的例子: 

public class ThreadTest {
	
	public static void main(String[] args) {
		ExecutorService executorService = Executors.newFixedThreadPool(10);
		executorService.execute(new Runnable() {
			public void run() {
				System.out.println("Asynchronous task");
			}
		});
		
		executorService.shutdown();
	}
}

這個例子其實很容易看懂,首先使用newFixedThreadPool() 工廠方法建立一個 ExecutorService ,上述程式碼建立了一個可以容納10個執行緒任務的執行緒池。然後向execute() 方法中傳遞一個非同步的 Runnable 介面的實現,這樣做會讓 ExecutorService 中的某個執行緒執行這個 Runnable執行緒。

由此可以看出ExecutorService使用執行緒池來管理執行緒,可以重複利用已經創建出來的執行緒而不是每次都必須新建立執行緒,節省了一部分的開銷。執行緒池可以很方便的管理執行緒的大小和當前在執行的執行緒數量。

除了上述的newFixedThreadPool實現方式, ExecutorService 例項的建立方式有以下幾種:
		ExecutorService executorService1 = Executors.newSingleThreadExecutor();
		ExecutorService executorService2 = Executors.newFixedThreadPool(10);
		ExecutorService executorService3 = Executors.newScheduledThreadPool(10);

說完了建立我們再看ExecutorService中的方法:
package java.util.concurrent;
import java.util.List;
import java.util.Collection;


public interface ExecutorService extends Executor {
   
    void shutdown();
    
    List<Runnable> shutdownNow();
    
    boolean isShutdown();
   
    boolean isTerminated();
    
    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;
   
    <T> Future<T> submit(Callable<T> task);
    
    <T> Future<T> submit(Runnable task, T result);
    
    Future<?> submit(Runnable task);

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

這裡有幾種不同的方式讓你將任務委託給一個ExecutorService:

1   execute(Runnable)
2   submit(Runnable)
3   submit(Callable)
4   invokeAny(...)
5   invokeAll(...)

execute(Runnable)

方法 execute(Runnable)接收一個 java.lang.Runnable 物件作為引數,並且以非同步的方式執行它。如下是一個使用 ExecutorService 執行 Runnable的例子:

	ExecutorService executorService =Executors.newSingleThreadExecutor();
		   
	executorService.execute(newRunnable() {
	       public void run() {
	          System.out.println("Asynchronous task");
	       }
        });
		       
	executorService.shutdown();

使用這種方式沒有辦法獲取執行 Runnable之後的結果,如果你希望獲取執行之後的返回值,就必須使用 接收 Callable 引數的 execute() 方法,後者將會在下文中提到。

submit(Runnable)

方法 submit(Runnable)同樣接收一個 Runnable 的實現作為引數,但是會返回一個 Future 物件。這個 Future 物件可以用於判斷 Runnable是否結束執行。如下是一個 ExecutorService 的 submit() 方法的例子:

	   Future future = executorService.submit(new Runnable() {
		   public void run() {
			   System.out.println("Asynchronous task");
		   }
	   });
	   //如果任務結束執行則返回 null
	   System.out.println("future.get()=" + future.get());


submit(Callable)

方法 submit(Callable) 和方法submit(Runnable) 比較類似,但是區別則在於它們接收不同的引數型別。Callable 的例項與 Runnable 的例項很類似,但是Callable 的 call() 方法可以返回一個結果。方法 Runnable.run() 則不能返回結果。

Callable 的返回值可以從方法submit(Callable) 返回的 Future 物件中獲取。如下是一個 ExecutorService Callable 的樣例:

	   Future future = executorService.submit(newCallable(){
		   public Object call() throwsException {
			   System.out.println("AsynchronousCallable");
			   return "CallableResult";
		   }
	   });
	   System.out.println("future.get()= " + future.get());

上述樣例程式碼會輸出如下結果:

Asynchronous Callable
future.get() = Callable Result

inVokeAny()

方法 invokeAny() 接收一個包含Callable 物件的集合作為引數。呼叫該方法不會返回 Future 物件,而是返回集合中某一個 Callable物件的結果,而且無法保證呼叫之後返回的結果是哪一個 Callable,只知道它是這些 Callable 中一個執行結束的 Callable 物件。

如果一個任務執行完畢或者丟擲異常,方法會取消其它的Callable 的執行。

以下是一個樣例:

	   Future future = executorService.submit(newCallable(){
		   public Object call() throwsException {
			   System.out.println("AsynchronousCallable");
			   return "CallableResult";
		   }
	   });
	   System.out.println("future.get()= " + future.get());
	   
	   ExecutorService executorService =Executors.newSingleThreadExecutor();
	   Set<Callable<String>>callables = new HashSet<Callable<String>>();
	   callables.add(newCallable<String>() {
		   public String call() throwsException {
			   return "Task1";
		   }
	   });
	   callables.add(newCallable<String>() {
		   public String call() throwsException {
			   return "Task2";
		   }
	   });
	   callables.add(newCallable<String>() {
		   public String call() throwsException {
			   return "Task3";
		   }
	   });
	   String result =executorService.invokeAny(callables);
	   System.out.println("result =" + result);
	   executorService.shutdown();


以上樣例程式碼會打印出在給定的集合中的某一個Callable 的返回結果。我嘗試運行了幾次,結果都在改變。有時候返回結果是”Task 1”,有時候是”Task 2”,等等。

invokeAll()

方法 invokeAll()會呼叫存在於引數集合中的所有 Callable 物件,並且返回一個包含 Future 物件的集合,你可以通過這個返回的集合來管理每個 Callable的執行結果。

需要注意的是,任務有可能因為異常而導致執行結束,所以它可能並不是真的成功運行了。但是我們沒有辦法通過Future 物件來了解到這個差異。

以下是一個程式碼樣例:

	   ExecutorService executorService =Executors.newSingleThreadExecutor();

	   Set<Callable<String>>callables = new HashSet<Callable<String>>();
	   
	   callables.add(newCallable<String>() {
		   public String call() throwsException {
			   return "Task1";
		   }
	   });
	   callables.add(newCallable<String>() {
		   public String call() throwsException {
			   return "Task2";
		   }
	   });
	   callables.add(newCallable<String>() {
		   public String call() throwsException {
			   return "Task3";
		   }
	   });
	     
	   List<Future<String>>futures = executorService.invokeAll(callables);
	    
	   for(Future<String> future :futures){
		   System.out.println("future.get = " +future.get());
	   }
	     
	   executorService.shutdown();


ExecuteService 服務的關閉

當使用 ExecutorService完畢之後,我們應該關閉它,這樣才能保證執行緒不會繼續保持執行狀態。

舉例來說,如果你的程式通過 main()方法啟動,並且主執行緒退出了你的程式,如果你還有一個活動的 ExecutorService 存在於你的程式中,那麼程式將會繼續保持執行狀態。存在於ExecutorService 中的活動執行緒會阻止Java虛擬機器關閉。

為了關閉在 ExecutorService中的執行緒,你需要呼叫 shutdown() 方法。ExecutorService並不會馬上關閉,而是不再接收新的任務,壹但所有的執行緒結束執行當前任務,ExecutorServie 才會真的關閉。所有在呼叫 shutdown()方法之前提交到 ExecutorService 的任務都會執行。

如果你希望立即關閉ExecutorService,你可以呼叫 shutdownNow()方法。這個方法會嘗試馬上關閉所有正在執行的任務,並且跳過所有已經提交但是還沒有執行的任務。但是對於正在執行的任務,是否能夠成功關閉它是無法保證的,有可能他們真的被關閉掉了,也有可能它會壹直執行到任務結束。這是一個最好的嘗試。




相關推薦

java執行ExecutorService解析

       前面幾篇部落格寫到的多執行緒實現基本都是顯式呼叫了Thread的start()方法,除了這種方法有沒有其他的實現方法呢,這裡我們來看下java.util.concurrent包下的Exe

java執行ExecutorService執行例項

瞭解了ExecutorService,現在就來看下具體業務的具體應用。 解決大量資料同時插入資料庫的多執行緒實現,解決其效能問題: 1、執行緒池 package com.akk.thread; import java.util.ArrayList; import java

Java執行簡單樣例銀行存取錢問題

Bank類 public class Bank { private static int money; public int getMoney(){ return money; } public void saveMon

Java執行和記憶體模型程序和執行基礎

Java多執行緒和記憶體模型(一) 由於java是執行在 JVM上 的,所以需要涉及到 JVM 的記憶體模型概念,需要理解記憶體模型,就需要多執行緒的基礎; 而執行緒是基於載體執行緒裡的,所以我們藉由作業系統的程序來講一講。 程序 什麼是程序?

Java執行ThreadLocal解析

一、ThreadLocal是什麼 ThreadLocal是一個本地執行緒副本變數工具類。主要用於將私有執行緒和該執行緒存放的副本物件做一個對映,各個執行緒之間的變數互不干擾,在高併發場景下,可以實現無狀態的呼叫,特別適用於各個執行緒依賴不通的變數值完成操作的場景。 二、從

PYTHON——執行訊號量Semaphore

  訊號量也是一把鎖,用來控制執行緒併發數的。   BoundedSemaphore或Semaphore管理一個內建的計數 器,每當呼叫acquire()時-1,呼叫release()時+1。       計數器不能小於0,當計數器為 0時,acquire()將阻塞執行緒至同

PYTHON——執行條件變數Condition

  條件變數(Condition)也是一把鎖,除了同步鎖的作用外,還具有線上程間通訊的功能。   有一類執行緒需要滿足條件之後才能夠繼續執行,Python提供了threading.Condition 物件用於條件變數執行緒的支援,它除了能提供RLock()或Lock()的方法外,還提供了 wait()、no

Java執行之基礎篇

上一篇介紹了Java多執行緒的基礎概念和synchronized關鍵字,這篇繼續介紹Java多執行緒的其他關鍵字和重要的方法。 一、volatile關鍵字 1.1 Java記憶體模型

Java執行之基礎篇

一、併發和並行 1.1 概念 1.2 比較 1.3 程序和執行緒 二、基礎概念 2.1 執

Java執行程式設計學習總結

  (尊重勞動成果,轉載請註明出處:https://blog.csdn.net/qq_25827845/article/details/84894463冷血之心的部落格) 系列文章: Java多執行緒程式設計學習總結(一) Java多執行緒程式設計學習總結(二) 前

Java 執行程式設計學習總結

定義篇 程序(Process)和執行緒(Thread) 怎樣實現多工處理(Multitasking)? 多工處理是同時執行多個任務的過程。我們使用多工處理來利用 CPU。可通過兩種方式實現多工處理: · 基於程序的多工 (多重處理) · 基於執行緒的多工處理

java執行之併發集合CopyOnWriteArrayList

CopyOnWriteArrayList:CopyOnWriteArrayList這是一個ArrayList的執行緒安全的變體,其原理大概可以通俗的理解為:初始化的時候只有一個容器,很常一段時間,這個容器資料、數量等沒有發生變化的時候,大家(多個執行緒),都是讀取(假設這段時

java執行之併發集合BlockingQueue

簡介 實現 package com.np.ota.test.queue; import java.util.concurrent.BlockingQueue; import java.ut

java執行-專題-聊聊併發Java SE1.6中的Synchronized

1 引言 在多執行緒併發程式設計中Synchronized一直是元老級角色,很多人都會稱呼它為重量級鎖,但是隨著Java SE1.6對Synchronized進行了各種優化之後,有些情況下它並不那麼重了,本文詳細介紹了Java SE1.6中為了減少獲得鎖和釋放鎖帶來的效

java執行之同步鎖Lock

      從Java5開始,提供了Lock, Lock提供了比synchronized方法和synchronized程式碼塊更廣泛的鎖定操作,Lock可以實現更靈活的結構,並且支援多個相關的Condition物件(物件監視器)。       Lock是控制多個執行緒對共享

Java執行-併發工具類等待執行完成的CountDownLatch

參考:https://www.jianshu.com/p/1716ce690637http://ifeve.com/talk-concurrency-countdownlatch/CountDownLatch是什麼CountDownLatch也叫閉鎖,在JDK1.5被引入,允

Java執行複習與鞏固--任務排程執行池ScheduledThreadPoolExecutor

1. 為什麼要使用ScheduledThreadPoolExecutor 在《Java多執行緒複習與鞏固(二)–執行緒相關工具類Timer和ThreadLocal的使用》提到過,Timer可以實現指定延時排程任務,還可以實現任務的週期性執行。但是Tim

JAVA執行-Lock的使用-公平鎖與非公平鎖

公平鎖與非公平鎖        鎖Lock分為:公平鎖和非公平鎖。        公平鎖:表示執行緒獲取鎖的順序是按照執行緒加鎖的順序來分配的,即先來先得的FIFO先進先出順序。        非公平

執行之ReentrantLock篇

昨天有說過後面講ReentrantLock,今天我們這篇幅就全域性的講解下,我們在Lock出來前,解決併發問題沒得選只能用Synchronized。 一.ReentrantLock PK synchronized       (1)synchronized是獨佔鎖,加鎖

十、JAVA執行JVM類載入器自動類載入器、雙親委託機制、類載入器名稱空間、執行時包、類的解除安裝等

  Jvm提供了三大內建的類載入器,不同的類載入器負責將不同的類載入到記憶體之中 根載入器(Bootstrap ClassLoader) 是最頂層的載入器,是由C++編寫的,主要負責虛擬機器核心類庫的載入,如整個java.lang包,根載入器是獲取不到引用的,因此