CompletableFuture創(chuàng)建及功能使用全面詳解
引言
FutureTask對(duì)于get()方法容易造成阻塞,所以在其基礎(chǔ)上誕生了CompletableFuture。他們的關(guān)系就像i和i++的關(guān)系,FutureTask能做的,CompletableFuture也能做,并且更加高效,功能更加擴(kuò)展。
創(chuàng)建CompletableFuture
在CompletableFuture源碼注釋中,作者并不希望開(kāi)發(fā)人員直接使用實(shí)例化去創(chuàng)建CompletableFuture,而是使用四大靜態(tài)方法。
實(shí)例化創(chuàng)建示例:
CompletableFuture completableFuture = new CompletableFuture();
CompletableFuture的四大靜態(tài)方法
supplyAsync(Supplier<U> supplier) ----有返回值
創(chuàng)建帶有返回值的異步任務(wù),類似方法ExecutorService的 submit(Callable<T> task)方法
CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " come in.....");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
});supplyAsync(Supplier<U> supplier,Executor executor)
ExecutorService threadPool = Executors.newFixedThreadPool(3);
// 如果自己沒(méi)有創(chuàng)建線程池,則使用默認(rèn)的ForkJoinPool線程池
CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " come in.....");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
}, threadPool);runAsync(Runnable runnable)----沒(méi)有返回值
創(chuàng)建沒(méi)有返回值的異步任務(wù),類似ExecutorService submit(Runnable task)方法
CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName() + " come in.....");
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(runAsync.get());runAsync(Runnable runnable,Executor executor)
ExecutorService threadPool = Executors.newFixedThreadPool(3);
// 如果沒(méi)有指定線程池,則使用默認(rèn)的ForkJoinPool線程池
CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> { System.out.println(Thread.currentThread().getName() + " come in.....");
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, threadPool);
System.out.println(runAsync.get());CompletableFuture獲取值
get()
最直接的獲值方法,但會(huì)拋出異常。源碼如下
/**
* Waits if necessary for this future to complete, and then
* returns its result.
* 等待線程計(jì)算完成以后獲取結(jié)果
* @return the result value
* @throws CancellationException if this future was cancelled
* @throws ExecutionException if this future completed exceptionally
* @throws InterruptedException if the current thread was interrupted
* while waiting
*/
public T get() throws InterruptedException, ExecutionException {
Object r;
return reportGet((r = result) == null ? waitingGet(true) : r);
}get(long timeout, TimeUnit unit)
如上,但可以加入等待時(shí)間,超過(guò)等待時(shí)間,拋出Timeout異常。源碼如下
/**
* Waits if necessary for at most the given time for this future
* to complete, and then returns its result, if available.
* 最多等待給定的時(shí)間以完成此計(jì)算,然后返回其結(jié)果(如果可用)
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return the result value
* @throws CancellationException if this future was cancelled
* @throws ExecutionException if this future completed exceptionally
* @throws InterruptedException if the current thread was interrupted
* while waiting
* @throws TimeoutException if the wait timed out
*/
public T get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
Object r;
long nanos = unit.toNanos(timeout);
return reportGet((r = result) == null ? timedGet(nanos) : r);
}
join()
直接獲取值,類似于get(),但與get()不同的是,join()不需要手動(dòng)拋出異常。代碼如下
/**
* Returns the result value when complete, or throws an
* (unchecked) exception if completed exceptionally. To better
* conform with the use of common functional forms, if a
* computation involved in the completion of this
* CompletableFuture threw an exception, this method throws an
* (unchecked) {@link CompletionException} with the underlying
* exception as its cause.
* 完成時(shí)返回結(jié)果值,如果異常完成則拋出(未選中)異常。
* 為了更好地符合通用函數(shù)形式的使用,如果完成此CompletableFuture所涉及的計(jì)算引發(fā)異常,
* 則此方法將引發(fā)(未選中){@link CompletionException},其原因是基礎(chǔ)異常。
*
* @return the result value
* @throws CancellationException if the computation was cancelled
* @throws CompletionException if this future completed
* exceptionally or a completion computation threw an exception
*/
public T join() {
Object r;
return reportJoin((r = result) == null ? waitingGet(false) : r);
}getNow(T valueIfAbsent)
和join()相同,不需要手動(dòng)拋出異常,在執(zhí)行過(guò)程中會(huì)返回遇見(jiàn)的異常。不同的是可以給定默認(rèn)值,如果執(zhí)行錯(cuò)誤或未完成,返回給定的默認(rèn)值。源碼如下
/**
* Returns the result value (or throws any encountered exception)
* if completed, else returns the given valueIfAbsent.
* 如果計(jì)算完成,則返回結(jié)果值(或引發(fā)任何遇到的異常),否則返回給定的默認(rèn)值
* @param valueIfAbsent the value to return if not completed
* @return the result value, if completed, else the given valueIfAbsent
* @throws CancellationException if the computation was cancelled
* @throws CompletionException if this future completed
* exceptionally or a completion computation threw an exception
*/
public T getNow(T valueIfAbsent) {
Object r;
return ((r = result) == null) ? valueIfAbsent : reportJoin(r);
}
complete
通俗來(lái)說(shuō),在complete之前設(shè)定一個(gè)等待時(shí)間,如果在等待時(shí)間內(nèi)沒(méi)有計(jì)算出結(jié)果,則返回true,并返回complete給定的默認(rèn)值。反之為false,返回原定計(jì)算的值。源碼如下
/**
* If not already completed, sets the value returned by {@link
* #get()} and related methods to the given value.
*
* @param value the result value
* @return {@code true} if this invocation caused this CompletableFuture
* to transition to a completed state, else {@code false}
*/
public boolean complete(T value) {
boolean triggered = completeValue(value);
postComplete();
return triggered;
}示例:
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (Exception e) {
e.printStackTrace();
}
return "123";
});
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(completableFuture.complete("給定的默認(rèn)值") + "\t" + completableFuture.join());返回結(jié)果:
true 給定的默認(rèn)值
CompletableFuture的回調(diào)
其中,帶Async后綴的函數(shù)表示需要連接的后置任務(wù)會(huì)被單獨(dú)提交到線程池中,從而相對(duì)前置任務(wù)來(lái)說(shuō)是異步運(yùn)行的。除此之外,兩者沒(méi)有其他區(qū)別。
thenApply / thenAccept / thenRun互相依賴
thenApply()-----有入?yún)⒂蟹祷?/h2>
表示獲取上一個(gè)任務(wù)的執(zhí)行結(jié)果作為新任務(wù)的執(zhí)行參數(shù),有返回值。但遇見(jiàn)錯(cuò)誤時(shí)會(huì)終止后面所有的線程。
通俗來(lái)說(shuō),任務(wù)A執(zhí)行完執(zhí)行B,B需要A的結(jié)果,并且B有返回值
thenApply也是有三個(gè)方法重載
// 后一個(gè)任務(wù)與前一個(gè)任務(wù)在同一線程執(zhí)行
public <U> CompletableFuture<U> thenApply(
Function<? super T,? extends U> fn) {
return uniApplyStage(null, fn);
}
// 后一個(gè)任務(wù)與前一個(gè)任務(wù)在不同線程中執(zhí)行
public <U> CompletableFuture<U> thenApplyAsync(
Function<? super T,? extends U> fn) {
return uniApplyStage(defaultExecutor(), fn);
}
//后一個(gè)任務(wù)使用自定義線程池執(zhí)行
public <U> CompletableFuture<U> thenApplyAsync(
Function<? super T,? extends U> fn, Executor executor) {
return uniApplyStage(screenExecutor(executor), fn);
}ps:示例
ExecutorService threadPool = Executors.newFixedThreadPool(3);
CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " come in.....");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
}, threadPool);
// 承接上一個(gè)多線程,有返回值
CompletableFuture<Integer> thenApply = supplyAsync.thenApply((result) -> {
System.out.println("上一線程結(jié)果" + result);
return ThreadLocalRandom.current().nextInt(10);
});
System.out.println(thenApply.get());
threadPool.shutdown();如果沒(méi)用使用thenApplyAsync()指定自己的線程池,線程池依舊使用的是默認(rèn)的ForkJoinPool線程池。
thenAccept() ----有入?yún)o(wú)返回
消費(fèi)型回調(diào)。接受上一個(gè)任務(wù)的結(jié)果作為參數(shù),但是沒(méi)有返回值。
通俗來(lái)說(shuō),任務(wù)A執(zhí)行完執(zhí)行B,B需要A的結(jié)果,B沒(méi)有返回值
// 后一個(gè)任務(wù)與前一個(gè)任務(wù)在同一線程執(zhí)行
public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
return uniAcceptStage(null, action);
}
// 后一個(gè)任務(wù)與前一個(gè)任務(wù)在不同線程中執(zhí)行
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) {
return uniAcceptStage(defaultExecutor(), action);
}
//后一個(gè)任務(wù)使用自定義線程池執(zhí)行
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,
Executor executor) {
return uniAcceptStage(screenExecutor(executor), action);
}示例:
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(2);
CompletableFuture<Void> async = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("111111");
return 1;
}, threadPool).thenApplyAsync((f) -> {
// 手動(dòng)創(chuàng)建異常
System.out.println("222222");
f += 2;
return f;
}, threadPool).thenAcceptAsync(f -> {
f += 3;
System.out.println("最終的值:" + f);
}, threadPool);
System.out.println(Thread.currentThread().getName() + " 先去做其他事情了");
async.join();
threadPool.shutdown();
}ps:只消費(fèi)
thenRun()----無(wú)入?yún)o(wú)返回
thenRun 的方法沒(méi)有入?yún)?,也沒(méi)有返回值。
通俗來(lái)說(shuō),任務(wù)A執(zhí)行完執(zhí)行B,并且B不需要A的結(jié)果,B沒(méi)有返回值
示例:
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(2);
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (Exception e) {
e.printStackTrace();
}
return "123";
},threadPool);
completableFuture.thenRunAsync(() -> {
System.out.println("thenRun 無(wú)入?yún)?,無(wú)返回值");
},threadPool);
completableFuture.join();
threadPool.shutdown();
}小結(jié)
thenApply()、thenAccept()、thenRun()的區(qū)別,示例代碼如下:
System.out.println(CompletableFuture.supplyAsync(()->"resultA").thenRun(()->{}).join());
System.out.println("《-----------------------------》");
System.out.println(CompletableFuture.supplyAsync(()->"resultA").thenAccept(System.out::println).join());
System.out.println("《-----------------------------》");
System.out.println(CompletableFuture.supplyAsync(()->"resultA").thenApply((f)-> "resultB").join());結(jié)果:
null
《------------------------------------------》
resultA
null
《-------------------------------------------》
resultB
exceptionally()
如果執(zhí)行任務(wù)出現(xiàn)異常,則執(zhí)行 exceptionally 中的代碼塊,并且需要一個(gè)返回值。
示例:
public static void main(String[] args) throws Exception {
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " come in.....");
int a = 10 / 0;
return 1;
});
//whenComplete:參數(shù)列表 (T t, U u),如果執(zhí)行過(guò)程正常完成,則執(zhí)行該分支
System.out.println(completableFuture.whenComplete((t, u) -> {
if (u==null) {
System.out.println(t);
}
//exceptionally :如果執(zhí)行過(guò)程出現(xiàn)異常,則走該分支
}).exceptionally((f) -> {
System.out.println("異常詳細(xì)信息:" + f.getMessage());
return 500;
}).get());
}whenComplete()
whenComplete 算是 exceptionally和thenApply的結(jié)合,將任務(wù)執(zhí)行的結(jié)果和異常作為回到方法的參數(shù),如果沒(méi)有發(fā)生異常則異常參數(shù)為null。源碼如下:
public CompletableFuture<T> whenComplete(
BiConsumer<? super T, ? super Throwable> action) {
return uniWhenCompleteStage(null, action);
}
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action) {
return uniWhenCompleteStage(asyncPool, action);
}
public CompletableFuture<T> whenCompleteAsync(
BiConsumer<? super T, ? super Throwable> action, Executor executor) {
return uniWhenCompleteStage(screenExecutor(executor), action);
}示例:
ExecutorService threadPool = Executors.newFixedThreadPool(3);
// 自定義線程池,可以防止主線程立刻結(jié)束,導(dǎo)致守護(hù)線程forkjoin的問(wèn)題
try {
CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() ->{
System.out.println(Thread.currentThread().getName() + " come in.....");
int result = ThreadLocalRandom.current().nextInt(10);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
}, threadPool).whenComplete((v,e) -> {
if (e==null) {
System.out.println(Thread.currentThread().getName() + " come in.....");
System.out.println("上一個(gè)線程執(zhí)行的結(jié)果:" + v);
}
}).exceptionally(e -> {
e.printStackTrace();
System.out.println("上一個(gè)線程執(zhí)行的異常" + e);
return null;
});
System.out.println(Thread.currentThread().getName() + " 忙其他的去了.....");
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}執(zhí)行結(jié)果:
handle()
表示獲取上一個(gè)任務(wù)的執(zhí)行結(jié)果作為新任務(wù)的執(zhí)行參數(shù),有返回值。相對(duì)于thenApply(),handle()可以將異常帶入下一個(gè)線程處理。源碼如下
public <U> CompletableFuture<U> handle(
BiFunction<? super T, Throwable, ? extends U> fn) {
return uniHandleStage(null, fn);
}示例:
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool(2);
CompletableFuture<Integer> handle = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("111111");
return 1;
}, threadPool).handle((f, n) -> {
// 手動(dòng)創(chuàng)建異常,跳過(guò)此線程后面的動(dòng)作
int i = 10/0;
System.out.println("222222");
f += 2;
return f;
}).handle((f, n) -> {
// 如果檢測(cè)到上一線程有異常,可以處理
if (n!=null) {
f=10;
}
System.out.println("333333");
f += 3;
return f;
}).whenComplete((f,e) -> {
if (e==null) {
System.out.println("計(jì)算結(jié)果為:" + f);
}
}).exceptionally(e -> {
e.printStackTrace();
System.out.println(e.getMessage());
return null;
});
System.out.println(Thread.currentThread().getName() + " 先去做其他事情了");
handle.join();
threadPool.shutdown();
}運(yùn)行結(jié)果:
main 先去做其他事情了
111111
333333
計(jì)算結(jié)果為:13
CompletableFuture對(duì)計(jì)算速度的選用
使用applyToEither可對(duì)兩個(gè)線程執(zhí)行速度進(jìn)行比較,獲取速度最快的執(zhí)行結(jié)果。源碼如下
public <U> CompletableFuture<U> applyToEither(
CompletionStage<? extends T> other, Function<? super T, U> fn) {
return orApplyStage(null, other, fn);
}
public <U> CompletableFuture<U> applyToEitherAsync(
CompletionStage<? extends T> other, Function<? super T, U> fn) {
return orApplyStage(asyncPool, other, fn);
}
public <U> CompletableFuture<U> applyToEitherAsync(
CompletionStage<? extends T> other, Function<? super T, U> fn,
Executor executor) {
return orApplyStage(screenExecutor(executor), other, fn);
}示例:
CompletableFuture<String> supplyAsyncA = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (Exception e) {
e.printStackTrace();
}
return "playA";
});
CompletableFuture<String> supplyAsyncB = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
return "playB";
});
CompletableFuture<String> applyToEither = supplyAsyncA.applyToEither(supplyAsyncB, f -> {
return f + " is winner!";
});
System.out.println(Thread.currentThread().getName() + "----" + applyToEither.join());applyToEither、acceptEither、runAfterEither的區(qū)別與前面回調(diào)函數(shù)的區(qū)別一致,在于是否有返回值
thenAcceptBoth
當(dāng)兩個(gè)CompletionStage都執(zhí)行完成后,把結(jié)果一塊交給thenAcceptBoth來(lái)進(jìn)行消耗
applyToEither
兩個(gè)CompletionStage,誰(shuí)執(zhí)行返回的結(jié)果快,我就用那個(gè)CompletionStage的結(jié)果進(jìn)行下一步的轉(zhuǎn)化操作。
acceptEither
兩個(gè)CompletionStage,誰(shuí)執(zhí)行返回的結(jié)果快,我就用那個(gè)CompletionStage的結(jié)果進(jìn)行下一步的消耗操作。
runAfterEither
兩個(gè)CompletionStage,任何一個(gè)完成了都會(huì)執(zhí)行下一步的操作(Runnable)
runAfterBoth
兩個(gè)CompletionStage,都完成了計(jì)算才會(huì)執(zhí)行下一步的操作(Runnable)
CompletableFuture多任務(wù)合并
thenCombine
thenCompose 方法允許你對(duì)兩個(gè) CompletionStage 進(jìn)行流水線操作,第一個(gè)操作完成時(shí),將其結(jié)果作為參數(shù)傳遞給第二個(gè)操作。,源碼如下
public <U,V> CompletableFuture<V> thenCombine(
CompletionStage<? extends U> other,
BiFunction<? super T,? super U,? extends V> fn) {
return biApplyStage(null, other, fn);
}
public <U,V> CompletableFuture<V> thenCombineAsync(
CompletionStage<? extends U> other,
BiFunction<? super T,? super U,? extends V> fn) {
return biApplyStage(asyncPool, other, fn);
}
public <U,V> CompletableFuture<V> thenCombineAsync(
CompletionStage<? extends U> other,
BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
return biApplyStage(screenExecutor(executor), other, fn);
}示例:
CompletableFuture<Integer> integerCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
System.out.println("線程一。。。。。。啟動(dòng)");
try {
TimeUnit.SECONDS.sleep(2);
} catch (Exception e) {
e.printStackTrace();
}
return 10;
});
CompletableFuture<Integer> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
System.out.println("線程二。。。。。。啟動(dòng)");
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
return 20;
});
CompletableFuture<Integer> result = integerCompletableFuture1.thenCombine(integerCompletableFuture2, (x, y) -> {
System.out.println("開(kāi)始合并。。。。。。。。");
return x + y;
});
System.out.println(result.join());結(jié)果:
線程一。。。。。。啟動(dòng)
線程二。。。。。。啟動(dòng)
開(kāi)始合并。。。。。。。。
30
allof
等待所有任務(wù)完成。源碼如下:
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
return andTree(cfs, 0, cfs.length - 1);
}示例:
ExecutorService threadPool = Executors.newFixedThreadPool(2);
CompletableFuture<String> integerCompletableFuture1 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
System.out.println("線程一。。。。。。啟動(dòng)");
} catch (Exception e) {
e.printStackTrace();
}
return "華為";
},threadPool);
CompletableFuture<String> integerCompletableFuture2 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println("線程二。。。。。。啟動(dòng)");
} catch (Exception e) {
e.printStackTrace();
}
return "小米";
},threadPool);
CompletableFuture<Void> allOf = CompletableFuture.allOf(integerCompletableFuture1, integerCompletableFuture2);
System.out.println(integerCompletableFuture1.join());
System.out.println(integerCompletableFuture2.join());
System.out.println("main..........end.........");
threadPool.shutdown();因?yàn)?code>allof需要等待所有線程執(zhí)行完畢,所以會(huì)先打印線程二。并等待線程一執(zhí)行完畢。
結(jié)果:
線程二。。。。。。啟動(dòng)
線程一。。。。。。啟動(dòng)
華為
小米
main..........end.........
anyof
等待其中一個(gè)任務(wù)完成。源碼如下:
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
return orTree(cfs, 0, cfs.length - 1);
}示例(在任務(wù)合并時(shí)不同,將allof改為anyof):
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(integerCompletableFuture1, integerCompletableFuture2);
System.out.println(anyOf.join());
System.out.println("main..........end.........");
threadPool.shutdown();因?yàn)榫€程二的執(zhí)行比線程一快,所以直接打印線程二。anyof返回的CompletableFuture,存儲(chǔ)的時(shí)先完成線程的返回結(jié)果。
結(jié)果:
線程二。。。。。。啟動(dòng)
小米
main..........end.........
線程一。。。。。。啟動(dòng)
以上就是CompletableFuture創(chuàng)建及功能使用全面詳解的詳細(xì)內(nèi)容,更多關(guān)于CompletableFuture功能創(chuàng)建的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
idea?intellij快速修復(fù)if語(yǔ)句缺少大括號(hào)的問(wèn)題
這篇文章主要介紹了idea?intellij快速修復(fù)if語(yǔ)句缺少大括號(hào)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
springboot集成開(kāi)發(fā)實(shí)現(xiàn)商場(chǎng)秒殺功能
這篇文章主要介紹了springboot集成實(shí)現(xiàn)商品秒殺功能,秒殺系統(tǒng)業(yè)務(wù)流程,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12
Spring實(shí)現(xiàn)IoC的多種方式小結(jié)
本篇文章主要介紹了Spring實(shí)現(xiàn)IoC的多種方式小結(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
SpringBoot熔斷機(jī)制之CircuitBreaker詳解
這篇文章主要介紹了SpringBoot熔斷機(jī)制之CircuitBreaker詳解,SpringBoot的熔斷機(jī)制在微服務(wù)架構(gòu)中扮演著重要角色,其中CircuitBreaker是其核心機(jī)制之一,用于防止服務(wù)的異常狀態(tài)影響到整個(gè)系統(tǒng)的運(yùn)作,需要的朋友可以參考下2023-10-10
Java報(bào)錯(cuò)java.awt.AWTException: AWT的解決方法
在Java圖形用戶界面(GUI)編程中,java.awt.AWTException是一個(gè)常見(jiàn)的異常,它通常與AWT(Abstract Window Toolkit)組件相關(guān),這個(gè)異常可能在嘗試進(jìn)行與窗口、圖形環(huán)境或系統(tǒng)剪貼板等操作時(shí)拋出,本文將詳細(xì)探討AWTException的成因,并提供多種解決方案2024-12-12
SpringBoot集成SOL鏈的詳細(xì)過(guò)程
Solanaj 是一個(gè)用于與 Solana 區(qū)塊鏈交互的 Java 庫(kù),它為 Java 開(kāi)發(fā)者提供了一套功能豐富的 API,使得在 Java 環(huán)境中可以輕松構(gòu)建與 Solana 區(qū)塊鏈交互的應(yīng)用程序,這篇文章主要介紹了SpringBoot集成SOL鏈的詳細(xì)過(guò)程,需要的朋友可以參考下2025-01-01
Maven安裝本地的jar包和創(chuàng)建帶模板的自定義項(xiàng)目的操作過(guò)程
這篇文章主要介紹了Maven安裝本地的jar包和創(chuàng)建帶模板的自定義項(xiàng)目,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-03-03

