提交Runnable任務(wù)
Runnable有一個run()函數(shù)尉姨,用于將耗時操作寫在其中,該函數(shù)沒有返回值。然后使用某個線程去執(zhí)行該runnable即可實現(xiàn)多線程,Thread類在調(diào)用start()函數(shù)后就是執(zhí)行的是Runnable的run()函數(shù)竟贯。
提交Callable任務(wù),F(xiàn)uture返回結(jié)果
Callable 在java 5中被引入逝钥, 作為Runnable 的一個對等(peer)屑那。 Callable除了有一個Call 方法而不是Run 方法外(和Runnable)本質(zhì)相同。 Call 方法有其它的能力去返回一個結(jié)果并且允許拋出檢查時異常。
Callable 任務(wù)提交所產(chǎn)生的結(jié)果可用后能夠被Future 獲取持际,F(xiàn)uture 可以被看作一個整理存儲Callable 計算結(jié)果的容器沃琅。callable的計算能持續(xù)在另一個線程中, 并且任何獲取一個Future 結(jié)果的嘗試都將被阻塞蜘欲,并且一旦(結(jié)果)變得可用益眉,便會返回結(jié)果。
public interface Future<V>Future 表示異步計算的結(jié)果姥份。它提供了檢查計算是否完成的方法呜叫,以等待計算的完成,并獲取計算的結(jié)果殿衰。計算完成后只能使用 get 方法來獲取結(jié)果,如有必要盛泡,計算完成前可以阻塞此方法闷祥。取消則由 cancel 方法來執(zhí)行。還提供了其他方法傲诵,以確定任務(wù)是正常完成還是被取消了凯砍。一旦計算完成,就不能再取消計算拴竹。如果為了可取消性而使用 Future 但又不提供可用的結(jié)果悟衩,則可以聲明 Future<?> 形式類型、并返回 null 作為底層任務(wù)的結(jié)果栓拜。
public interface Callable<V>返回結(jié)果并且可能拋出異常的任務(wù)座泳。實現(xiàn)者定義了一個不帶任何參數(shù)的叫做 call 的方法。
Callable 接口類似于 Runnable幕与,兩者都是為那些其實例可能被另一個線程執(zhí)行的類設(shè)計的挑势。但是 Runnable 不會返回結(jié)果,并且無法拋出經(jīng)過檢查的異常啦鸣。
Runnable 提供了一種包裹要被在一個不同的線程中執(zhí)行的代碼的方式潮饱。它有一個缺陷, 不能從執(zhí)行中返回結(jié)果诫给。僅有的一種從一個Runnable 的執(zhí)行中返回值的方式是把結(jié)果賦值給一個在Runnable 外部作用域中可訪問的變量香拉。
二者區(qū)別
Callable 和 Future接口的區(qū)別
- Callable規(guī)定的方法是call(),而Runnable規(guī)定的方法是run().
- Callable的任務(wù)執(zhí)行后可返回值中狂,而Runnable的任務(wù)是不能返回值的凫碌。
- call()方法可拋出異常,而run()方法是不能拋出異常的吃型。
- 運行Callable任務(wù)可拿到一個Future對象证鸥, Future表示異步計算的結(jié)果。
- 它提供了檢查計算是否完成的方法,以等待計算的完成枉层,并檢索計算的結(jié)果泉褐。
- 通過Future對象可了解任務(wù)執(zhí)行情況,可取消任務(wù)的執(zhí)行鸟蜡,還可獲取任務(wù)執(zhí)行的結(jié)果膜赃。
- Callable是類似于Runnable的接口,實現(xiàn)Callable接口的類和實現(xiàn)Runnable的類都是可被其它線程執(zhí)行的任務(wù)揉忘。
使用案例
模擬任務(wù)
public class PollingResult {
public Random random = new Random();
public void executeTask(int sleepTime) {
try {
int value = random.nextInt(10);
while(true){
// 模擬輪詢過程跳座,隨機耗時1-5s
Thread.sleep(sleepTime);
if ( value % 2 == 0) {
// 當(dāng)前隨機數(shù)是偶數(shù)直接結(jié)束循環(huán)
break;
}
value = random.nextInt(10);
}
System.out.println("SubmitRunnableTask:"+ value + "是偶數(shù)!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public Integer executeTask(int sleepTime, boolean callback) {
try {
int value = random.nextInt(10);
while(true){
// 模擬輪詢過程泣矛,隨機耗時1-5s
Thread.sleep(sleepTime);
if ( value % 2 == 0) {
// 當(dāng)前隨機數(shù)是偶數(shù)直接結(jié)束循環(huán)
break;
}
value = random.nextInt(10);
}
return value;
} catch (InterruptedException e) {
e.printStackTrace();
}
return 0;
}
}
提交Callback任務(wù)
public class SubmitCallableTask {
/**
* 構(gòu)造一個并發(fā)數(shù)是5疲眷,阻塞隊列是0,一滿就拋異常的線程池
*/
public static ExecutorService THREAD_POOL = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<>());
public Random random = new Random(10);
private PollingResult pollingResult = new PollingResult();
public void execute() {
Future<Integer> future = THREAD_POOL.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return pollingResult.executeTask(random.nextInt(1000), true);
}
});
try {
// get() 方法用來獲取執(zhí)行結(jié)果您朽,這個方法會產(chǎn)生阻塞狂丝,會一直等到任務(wù)執(zhí)行完畢才返回
System.out.println("SubmitCallableTask:"+future.get() + "是偶數(shù)!");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
提交Runnable任務(wù)
public class SubmitRunnableTask {
/**
* 構(gòu)造一個并發(fā)數(shù)是5哗总,阻塞隊列是0几颜,一滿就拋異常的線程池
*/
public static ExecutorService THREAD_POOL = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<>());
public Random random = new Random(10);
private PollingResult pollingResult = new PollingResult();
public void execute() {
THREAD_POOL.submit(() -> {
// 提交帶執(zhí)行的任務(wù)
pollingResult.executeTask(random.nextInt(1000));
});
}
}
測試并發(fā)數(shù)
public class MainTask {
private static SubmitRunnableTask submitRunnableTask = new SubmitRunnableTask();
private static SubmitCallableTask submitCallableTask = new SubmitCallableTask();
public static void main(String[] args) {
// 提交異步任務(wù),這個不會拋異常
for(int i=0;i<10;i++){
submitCallableTask.execute();
}
// 同時提交10個任務(wù)讯屈,肯定會拋異常
for(int i=0;i<10;i++){
submitRunnableTask.execute();
}
}
}