Java并发编程—说说Runnable与Callable
原文作者:每天一點(diǎn)
原文地址:說說Runnable與Callable
首先,我們先看看使用Callable創(chuàng)建線程與使用Runable的區(qū)別:
import java.util.concurrent.Callable;//實(shí)現(xiàn)Runable class MyThread implements Runnable {@Overridepublic void run() {} }//實(shí)現(xiàn)Callable class MyThread1 implements Callable<Integer> {@Overridepublic Integer call() throws Exception {return null;} }首先,實(shí)現(xiàn)Callable而重寫的方法具有返回值,并且擁有泛型,這提高了線程的細(xì)粒度。
實(shí)現(xiàn)Runable接口創(chuàng)建線程方式:
//實(shí)現(xiàn)Runable創(chuàng)建線程的方式 MyThread myThread = new MyThread(); Thread thread = new Thread(myThread);實(shí)現(xiàn)Callable接口創(chuàng)建線程方式
查閱API我們可以發(fā)現(xiàn),在Thread的構(gòu)造方法中并沒有使用Callable作為參數(shù)的構(gòu)造器。解決辦法:我們先查看Runable接口,
可以發(fā)現(xiàn)有一個(gè)FutureTask的實(shí)現(xiàn)類,點(diǎn)進(jìn)這個(gè)實(shí)現(xiàn)類,我們可以發(fā)現(xiàn)在這個(gè)類的構(gòu)造方法中就可以傳Callable對(duì)象
所以我們可以借助FutureTask這個(gè)類,具體創(chuàng)建代碼如下:
//實(shí)現(xiàn)Callable創(chuàng)建線程的方式 FutureTask futureTask = new FutureTask(new MyThread1()); Thread thread1 = new Thread(futureTask);這里有個(gè)細(xì)節(jié):如果我們?cè)谑咕€程睡眠5秒鐘,然后使用futureTask.get()方法,會(huì)發(fā)現(xiàn)結(jié)果會(huì)等5秒才出現(xiàn),說明get()方法是有阻塞效果
//實(shí)現(xiàn)Callable class MyThread1 implements Callable<Integer> {@Overridepublic Integer call() throws Exception {System.out.println("進(jìn)入方法中");Thread.sleep(5000);return 1000;} }public class Test {public static void main(String[] args) {//實(shí)現(xiàn)Callable創(chuàng)建線程的方式FutureTask futureTask = new FutureTask(new MyThread1());new Thread(futureTask, "AAA").start();try {System.out.println(futureTask.get());System.out.println("main");} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}} }并且只執(zhí)行了一次,因?yàn)橐粋€(gè)futureTask,不管幾個(gè)線程調(diào)用,調(diào)用的都是同一個(gè)futureTask對(duì)象
Callable接口:
public interface Callable<V> {V call() throws Exception; }Runnable接口:
public interface Runnable {public abstract void run(); }相同點(diǎn):
不同點(diǎn):
注意點(diǎn):
- Callable接口支持返回執(zhí)行結(jié)果,此時(shí)需要調(diào)用FutureTask.get()方法實(shí)現(xiàn),此方法會(huì)阻塞主線程直到獲取‘將來’結(jié)果;當(dāng)不調(diào)用此方法時(shí),主線程不會(huì)阻塞!
寫此篇的原因是一次面試中問到Callable與Runnable的區(qū)別,當(dāng)時(shí)用的多的是Runnable,而Callable使用很少!比較了兩者后(網(wǎng)上查了不少),發(fā)現(xiàn)Callable在很多特殊的場(chǎng)景下還是很有用的!最后留點(diǎn)抄的代碼,加深對(duì)Callable的認(rèn)識(shí)!
package com.inte.fork; import java.util.*; import java.util.concurrent.*; import static java.util.Arrays.asList;public class Sums {static class Sum implements Callable<Long> {private final long from;private final long to;Sum(long from, long to) {this.from = from;this.to = to;}@Overridepublic Long call() {long acc = 0;for (long i = from; i <= to; i++) {acc = acc + i;}System.out.println(Thread.currentThread().getName() + " : " + acc);return acc;}}public static void main(String[] args) throws Exception {ExecutorService executor = Executors.newFixedThreadPool(3);List<Future<Long>> results = executor.invokeAll(asList(new Sum(0, 10), new Sum(0, 1_000), new Sum(0, 1_000_000)));executor.shutdown();for (Future<Long> result : results) {System.out.println(result.get());}} }總結(jié)
以上是生活随笔為你收集整理的Java并发编程—说说Runnable与Callable的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java集合—List如何一边遍历,一边
- 下一篇: Java并发编程—notify和noti