一、使用Future實現非同步調用
Java中提供了Future介面及其實現類FutureTask。使用Future和FutureTask,能夠在調用一個方法時立即返回,不必等待方法執行完畢,可以通過Future對象獲得方法執行結果。這就是常見的非同步調用。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class FutureDemo {
public static void main(String[] args) {
Callable callable = () -> {
Thread.sleep(2000);//休眠2秒模擬耗時任務
return 100;
};
FutureTask futureTask = new FutureTask(callable);
new Thread(futureTask).start();
try {
System.out.println("非同步調用返回結果:" + futureTask.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
上述代碼中,通過Callable創建一個耗時任務。FutureTask的作用是將Callable封裝成一個Future實例,通過Future實例能夠獲得非同步調用結果。
二、使用CompletableFuture實現非同步調用
JDK1.8之後,Java提供了新的非同步編程API——CompletableFuture,用來處理非同步編程中的複雜場景。
CompletableFuture是Future的實現,而且它提供了更多的操作方法,如組合、轉化和聚合等。
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureDemo {
public static void main(String[] args) {
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);//休眠2秒模擬耗時任務
} catch (InterruptedException e) {
e.printStackTrace();
}
return 100;
});
try {
System.out.println("非同步調用返回結果:" + future.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
上述代碼中,使用CompletableFuture.supplyAsync()方法創建非同步任務,該方法會在ForkJoinPool.commonPool()線程池中執行,返回一個CompletableFuture實例。
三、非同步調用異常處理
在非同步調用過程中,異常的處理要比同步調用更複雜。非同步調用的結果是Future或者CompletableFuture實例,需要使用try…catch方法,捕獲執行過程中可能發生的異常。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class FutureDemo {
public static void main(String[] args) {
Callable callable = () -> {
if (Math.random() < 0.5) {
throw new RuntimeException("調用失敗");
} else {
Thread.sleep(2000);//休眠2秒模擬耗時任務
return 100;
}
};
FutureTask futureTask = new FutureTask(callable);
new Thread(futureTask).start();
try {
System.out.println("非同步調用返回結果:" + futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
System.out.println("調用失敗原因:" + e.getCause().getMessage());
}
}
}
上述代碼中,Callable隨機拋出了一個RuntimeException異常。由於非同步執行結果在get()方法處才返回,因此get()方法需要捕獲ExecutionException異常,並且通過getCause()方法獲取原始的RuntimeException異常。
四、使用線程池實現非同步調用
在非同步調用中,如果需要大量地創建線程,可能會引起線程創建過多的問題。在這種情況下,可以使用線程池優化資源消耗和性能問題。
import java.util.concurrent.*;
public class ThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(1);
Future future = executorService.submit(() -> {
try {
Thread.sleep(2000);//休眠2秒模擬耗時任務
} catch (InterruptedException e) {
e.printStackTrace();
}
return 100;
});
executorService.shutdown();
try {
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
System.out.println("調用失敗原因:" + e.getCause().getMessage());
}
}
}
上述代碼中,使用Executors.newFixedThreadPool()方法創建線程池,之後使用submit()方法創建非同步任務。submit()方法返回的是Future實例,可以通過get()方法獲取非同步任務執行結果。
五、使用註解實現非同步調用
Spring中提供了@Async註解支持非同步方法執行,只需在需要非同步執行的方法上加上@Async註解,就可以非同步執行該方法。
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
@Async
public void asyncMethod() {
try {
Thread.sleep(2000);//休眠2秒模擬耗時任務
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("非同步方法執行完成。");
}
}
上述代碼中,@Async註解表示非同步方法執行。在Spring容器中,非同步方法會在新的線程中執行,不會阻塞其他任務的執行。
六、結語
本文介紹了Java中非同步調用的多種方式,包括使用Future、CompletableFuture、線程池、註解等。非同步調用能夠提高系統的並發處理能力,避免了阻塞線程等問題,但是也需要開發者注意異常處理等問題,以便保證系統的高可用性。
原創文章,作者:VJKI,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/149978.html
微信掃一掃
支付寶掃一掃