Java5 并發學習
在Java5之后,并發線程這塊發生了根本的變化,最重要的莫過于新的啟動、調度、管理線程的一大堆API了。在Java5以后,通過 Executor來啟動線程比用Thread的start()更好。在新特征中,可以很容易控制線程的啟動、執行和關閉過程,還可以很容易使用線程池的特性。
一、創建任務
任務就是一個實現了Runnable接口的類。
創建的時候實run方法即可。
二、執行任務
通過java.util.concurrent.ExecutorService接口對象來執行任務,該接口對象通過工具類java.util.concurrent.Executors的靜態方法來創建。
Executors此包中所定義的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 類的工廠和實用方法。
ExecutorService提供了管理終止的方法,以及可為跟蹤一個或多個異步任務執行狀況而生成 Future 的方法。 可以關閉 ExecutorService,這將導致其停止接受新任務。關閉后,執行程序將最后終止,這時沒有任務在執行,也沒有任務在等待執行,并且無法提交新任 務。
executorService.execute(new TestRunnable());
1、創建ExecutorService
通過工具類java.util.concurrent.Executors的靜態方法來創建。
Executors此包中所定義的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 類的工廠和實用方法。
比如,創建一個ExecutorService的實例,ExecutorService實際上是一個線程池的管理工具:
ExecutorService executorService = Executors.newCachedThreadPool();
ExecutorService executorService = Executors.newFixedThreadPool(3);
ExecutorService executorService = Executors.newSingleThreadExecutor();
2、將任務添加到線程去執行
當將一個任務添加到線程池中的時候,線程池會為每個任務創建一個線程,該線程會在之后的某個時刻自動執行。
三、關閉執行服務對象
executorService.shutdown();
四、綜合實例
package concurrent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by IntelliJ IDEA.
*
* @author leizhimin 2008-11-25 14:28:59
*/
public class TestCachedThreadPool {
public static void main(String[] args) {
// ExecutorService executorService = Executors.newCachedThreadPool();
ExecutorService executorService = Executors.newFixedThreadPool(5);
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by IntelliJ IDEA.
*
* @author leizhimin 2008-11-25 14:28:59
*/
public class TestCachedThreadPool {
public static void main(String[] args) {
// ExecutorService executorService = Executors.newCachedThreadPool();
ExecutorService executorService = Executors.newFixedThreadPool(5);
// ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
executorService.execute(new TestRunnable());
System.out.println("************* a" + i + " *************" );
}
executorService.shutdown();
}
}
class TestRunnable implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName() + "線程被調用了。" );
while (true ) {
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
for (int i = 0; i < 5; i++) {
executorService.execute(new TestRunnable());
System.out.println("************* a" + i + " *************" );
}
executorService.shutdown();
}
}
class TestRunnable implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName() + "線程被調用了。" );
while (true ) {
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
運行結果:
************* a0 *************
************* a1 *************
pool-1-thread-2線程被調用了。
************* a2 *************
pool-1-thread-3線程被調用了。
pool-1-thread-1線程被調用了。
************* a3 *************
************* a4 *************
pool-1-thread-4線程被調用了。
pool-1-thread-5線程被調用了。
pool-1-thread-2
pool-1-thread-1
pool-1-thread-3
pool-1-thread-5
pool-1-thread-4
pool-1-thread-2
pool-1-thread-1
pool-1-thread-3
pool-1-thread-5
pool-1-thread-4
......
************* a1 *************
pool-1-thread-2線程被調用了。
************* a2 *************
pool-1-thread-3線程被調用了。
pool-1-thread-1線程被調用了。
************* a3 *************
************* a4 *************
pool-1-thread-4線程被調用了。
pool-1-thread-5線程被調用了。
pool-1-thread-2
pool-1-thread-1
pool-1-thread-3
pool-1-thread-5
pool-1-thread-4
pool-1-thread-2
pool-1-thread-1
pool-1-thread-3
pool-1-thread-5
pool-1-thread-4
......
五、獲取任務的執行的返回值
在Java5之后,任務分兩類:一類是實現了Runnable接口的類,一類是實現了Callable接口的類。兩者都可以被 ExecutorService執行,但是Runnable任務沒有返回值,而Callable任務有返回值。并且Callable的call()方法只 能通過ExecutorService的submit ( Callable <T> task) 方法來執行,并且返回一個 <T> Future <T>,是表示任務等待完成的 Future。
public interface Callable<V>
返回結果并且可能拋出異常的任務。實現者定義了一個不帶任何參數的叫做 call 的方法。
Callable 接口類似于
Runnable
,兩者都是為那些其實例可能被另一個線程執行的類設計的。但是 Runnable 不會返回結果,并且無法拋出經過檢查的異常。 Executors
類包含一些從其他普通形式轉換成 Callable 類的實用方法。Callable中的call()方法類似Runnable的run()方法,就是前者有返回值,后者沒有。
當將一個Callable的對象傳遞給ExecutorService的submit方法,則該call方法自動在一個線程上執行,并且會返回執行結果Future對象。
同樣,將Runnable的對象傳遞給ExecutorService的submit方法,則該run方法自動在一個線程上執行,并且會返回執行結果Future對象,但是在該Future對象上調用get方法,將返回null。
遺憾的是,在Java API文檔中,這塊介紹的很糊涂,估計是翻譯人員還沒搞清楚的緣故吧。或者說是注釋不到位。下面看個例子:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* Callable接口測試
*
* @author leizhimin 2008-11-26 9:20:13
*/
public class CallableDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> resultList = new ArrayList<Future<String>>();
//創建10個任務并執行
for (int i = 0; i < 10; i++) {
//使用ExecutorService執行Callable類型的任務,并將結果保存在future變量中
Future<String> future = executorService.submit(new TaskWithResult(i));
//將任務執行結果存儲到List中
resultList.add(future);
}
//遍歷任務的結果
for (Future<String> fs : resultList) {
try {
System.out.println(fs.get()); //打印各個線程(任務)執行的結果
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
//啟動一次順序關閉,執行以前提交的任務,但不接受新任務。如果已經關閉,則調用沒有其他作用。
executorService.shutdown();
}
}
}
}
class TaskWithResult implements Callable<String> {
private int id;
public TaskWithResult(int id) {
this .id = id;
}
/**
* 任務的具體過程,一旦任務傳給ExecutorService的submit方法,則該方法自動在一個線程上執行。
*
* @return
* @throws Exception
*/
public String call() throws Exception {
System.out.println("call()方法被自動調用,干活!!! " + Thread.currentThread().getName());
//一個模擬耗時的操作
for (int i = 999999; i > 0; i--) ;
return "call()方法被自動調用,任務的結果是:" + id + " " + Thread.currentThread().getName();
}
}
import java.util.List;
import java.util.concurrent.*;
/**
* Callable接口測試
*
* @author leizhimin 2008-11-26 9:20:13
*/
public class CallableDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> resultList = new ArrayList<Future<String>>();
//創建10個任務并執行
for (int i = 0; i < 10; i++) {
//使用ExecutorService執行Callable類型的任務,并將結果保存在future變量中
Future<String> future = executorService.submit(new TaskWithResult(i));
//將任務執行結果存儲到List中
resultList.add(future);
}
//遍歷任務的結果
for (Future<String> fs : resultList) {
try {
System.out.println(fs.get()); //打印各個線程(任務)執行的結果
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
//啟動一次順序關閉,執行以前提交的任務,但不接受新任務。如果已經關閉,則調用沒有其他作用。
executorService.shutdown();
}
}
}
}
class TaskWithResult implements Callable<String> {
private int id;
public TaskWithResult(int id) {
this .id = id;
}
/**
* 任務的具體過程,一旦任務傳給ExecutorService的submit方法,則該方法自動在一個線程上執行。
*
* @return
* @throws Exception
*/
public String call() throws Exception {
System.out.println("call()方法被自動調用,干活!!! " + Thread.currentThread().getName());
//一個模擬耗時的操作
for (int i = 999999; i > 0; i--) ;
return "call()方法被自動調用,任務的結果是:" + id + " " + Thread.currentThread().getName();
}
}
運行結果:
call()方法被自動調用,干活!!! pool-1-thread-1
call()方法被自動調用,干活!!! pool-1-thread-3
call()方法被自動調用,干活!!! pool-1-thread-4
call()方法被自動調用,干活!!! pool-1-thread-6
call()方法被自動調用,干活!!! pool-1-thread-2
call()方法被自動調用,干活!!! pool-1-thread-5
call()方法被自動調用,任務的結果是:0 pool-1-thread-1
call()方法被自動調用,任務的結果是:1 pool-1-thread-2
call()方法被自動調用,干活!!! pool-1-thread-2
call()方法被自動調用,干活!!! pool-1-thread-6
call()方法被自動調用,干活!!! pool-1-thread-4
call()方法被自動調用,任務的結果是:2 pool-1-thread-3
call()方法被自動調用,干活!!! pool-1-thread-3
call()方法被自動調用,任務的結果是:3 pool-1-thread-4
call()方法被自動調用,任務的結果是:4 pool-1-thread-5
call()方法被自動調用,任務的結果是:5 pool-1-thread-6
call()方法被自動調用,任務的結果是:6 pool-1-thread-2
call()方法被自動調用,任務的結果是:7 pool-1-thread-6
call()方法被自動調用,任務的結果是:8 pool-1-thread-4
call()方法被自動調用,任務的結果是:9 pool-1-thread-3
Process finished with exit code 0
call()方法被自動調用,干活!!! pool-1-thread-3
call()方法被自動調用,干活!!! pool-1-thread-4
call()方法被自動調用,干活!!! pool-1-thread-6
call()方法被自動調用,干活!!! pool-1-thread-2
call()方法被自動調用,干活!!! pool-1-thread-5
call()方法被自動調用,任務的結果是:0 pool-1-thread-1
call()方法被自動調用,任務的結果是:1 pool-1-thread-2
call()方法被自動調用,干活!!! pool-1-thread-2
call()方法被自動調用,干活!!! pool-1-thread-6
call()方法被自動調用,干活!!! pool-1-thread-4
call()方法被自動調用,任務的結果是:2 pool-1-thread-3
call()方法被自動調用,干活!!! pool-1-thread-3
call()方法被自動調用,任務的結果是:3 pool-1-thread-4
call()方法被自動調用,任務的結果是:4 pool-1-thread-5
call()方法被自動調用,任務的結果是:5 pool-1-thread-6
call()方法被自動調用,任務的結果是:6 pool-1-thread-2
call()方法被自動調用,任務的結果是:7 pool-1-thread-6
call()方法被自動調用,任務的結果是:8 pool-1-thread-4
call()方法被自動調用,任務的結果是:9 pool-1-thread-3
Process finished with exit code 0
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!