日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

线程2---异步1

發(fā)布時(shí)間:2023/12/19 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 线程2---异步1 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  在Java中什么是同步?什么是異步?對(duì)于這兩個(gè)概念我們必須要明確。只有明確這兩個(gè)概念,才會(huì)在明確在什么場(chǎng)景下使用同步以及異步。

  在這里我可以形象的舉個(gè)例子來(lái)辨明這兩個(gè)概念:

1.同步與異步 同步和異步關(guān)注的是消息通信機(jī)制 (synchronous communication/ asynchronous communication) 所謂同步,就是在發(fā)出一個(gè)*調(diào)用*時(shí),在沒(méi)有得到結(jié)果之前,該*調(diào)用*就不返回。但是一旦調(diào)用返回,就得到返回值了。換句話說(shuō),就是由*調(diào)用者*主動(dòng)等待這個(gè)*調(diào)用*的結(jié)果。 而異步則是相反,*調(diào)用*在發(fā)出之后,這個(gè)調(diào)用就直接返回了,所以沒(méi)有返回結(jié)果。換句話說(shuō),當(dāng)一個(gè)異步過(guò)程調(diào)用發(fā)出后,調(diào)用者不會(huì)立刻得到結(jié)果。而是在*調(diào)用*發(fā)出后,*被調(diào)用者*通過(guò)狀態(tài)、通知來(lái)通知調(diào)用者,或通過(guò)回調(diào)函數(shù)處理這個(gè)調(diào)用。 典型的異步編程模型舉個(gè)通俗的例子:你打電話問(wèn)書店老板有沒(méi)有《分布式系統(tǒng)》這本書, 如果是同步通信機(jī)制,書店老板會(huì)說(shuō),你稍等,”我查一下",然后開(kāi)始查啊查,等查好了(可能是5秒,也可能是一天)告訴你結(jié)果(返回結(jié)果)。 而異步通信機(jī)制,書店老板直接告訴你我查一下啊,查好了打電話給你,然后直接掛電話了(不返回結(jié)果)。然后查好了,他會(huì)主動(dòng)打電話給你。 在這里老板通過(guò)“回電”這種方式來(lái)回調(diào)。 2. 阻塞與非阻塞阻塞和非阻塞關(guān)注的是程序在等待調(diào)用結(jié)果(消息,返回值)時(shí)的狀態(tài).阻塞調(diào)用是指調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起。調(diào)用線程只有在得到結(jié)果之后才會(huì)返回。非阻塞調(diào)用指在不能立刻得到結(jié)果之前,該調(diào)用不會(huì)阻塞當(dāng)前線程。還是上面的例子, 你打電話問(wèn)書店老板有沒(méi)有《分布式系統(tǒng)》這本書,你如果是阻塞式調(diào)用,你會(huì)一直把自己“掛起”,直到得到這本書有沒(méi)有的結(jié)果,如果是非阻塞式調(diào)用,你不管老板有沒(méi)有告訴你,你自己先一邊去玩了, 當(dāng)然你也要偶爾過(guò)幾分鐘check一下老板有沒(méi)有返回結(jié)果。在這里阻塞與非阻塞與是否同步異步無(wú)關(guān)。跟老板通過(guò)什么方式回答你結(jié)果無(wú)關(guān)。 在開(kāi)始解決上述問(wèn)題之前我們來(lái)討論下使用Callbale接口來(lái)創(chuàng)建線程。 @FunctionalInterface public interface Callable<V> {/*** 返回一個(gè)任務(wù)的結(jié)果,或者拋出一個(gè)異常(如果不能計(jì)算結(jié)果)*/V call() throws Exception; }

Callable接口是一個(gè)函數(shù)式接口,其中call()方法的返回值的類型就是Callable接口的泛型的類型。但是Callable接口怎么和線程扯上關(guān)系呢?? FutureTask類存在一個(gè)構(gòu)造器:如下所示:

FutureTask(Callable<V> callable)

其中的參數(shù)正式Callable接口對(duì)象;FutureTask類又是實(shí)現(xiàn)接口RunnableFuture接口:

public class FutureTask<V> implements RunnableFuture<V>

接著看:

public interface RunnableFuture<V> extends Runnable, Future<V> {void run(); }

最終的還是繼承了Runnable接口和Future接口,為了說(shuō)明關(guān)系,我們畫出類圖:

package com._thread;import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask;public class CallableThread implements Callable<String> {/*** 票的張數(shù)為50張,總共100個(gè)人買票*/private int ticket = 50;// 表示票的張數(shù) @Overridepublic String call() throws Exception {for (int i = 0; i < 100; i++) {if (ticket > 0) {System.out.println("買票:ticket = " + this.ticket--);}}return "票賣光了!";}public static void main(String[] args) throws InterruptedException, ExecutionException {// 創(chuàng)建Callable接口對(duì)象 在這里我創(chuàng)建了兩個(gè)任務(wù)對(duì)象Callable<String> callable1 = new CallableThread();Callable<String> callable2 = new CallableThread();// 將創(chuàng)建的callable任務(wù)對(duì)象存儲(chǔ)在FutureTask對(duì)象中FutureTask<String> task1=new FutureTask<String>(callable1);FutureTask<String> task2=new FutureTask<String>(callable2);// 啟動(dòng)線程執(zhí)行任務(wù)new Thread(task1).start();new Thread(task2).start();// 上述代碼只是執(zhí)行線程,callable接口是可以產(chǎn)生結(jié)果的,futuretask可以獲取結(jié)果// 調(diào)用get()方法可以阻止當(dāng)前執(zhí)行的線程獲取結(jié)果System.out.println("線程A的返回結(jié)果是:"+task1.get());System.out.println("線程B的返回結(jié)果是:"+task2.get());} }

這是使用callable接口來(lái)創(chuàng)建線程的一種實(shí)現(xiàn)過(guò)程;好了現(xiàn)在讓我們討論Java異步編程吧!

上面的圖可以說(shuō)明我們的一個(gè)買書的過(guò)程,在Java中可以視這個(gè)操作為同步操作:

package com._thread;public class SlowWorker {public SlowWorker() {}public void doWork() {try {System.out.println("==== 找書, 找書, 找書 ====== ");Thread.sleep(2000);System.out.println("==== OK! ======");} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args) {SlowWorker worker = new SlowWorker();// 主線程模擬買書的人,doWork()方法模擬書店老板的行為!System.out.println("老板,我要買書" + new java.util.Date());worker.doWork();System.out.println("... 老板在找書的過(guò)程中我可以干些事情嗎!....");System.out.println("書買到了" + new java.util.Date());System.exit(0);} }

看運(yùn)行結(jié)果:

老板,我要買書Sun Jan 21 01:49:35 CST 2018 ==== 找書, 找書, 找書 ====== ==== OK! ====== ... 老板在找書的過(guò)程中我可以干些事情嗎!.... 書買到了Sun Jan 21 01:49:37 CST 2018

以上的操作確實(shí)是一種同步的操作;主線程運(yùn)行開(kāi)始后,調(diào)用doWork()方法,而doWork()方法需要休眠2s.但是主線程沒(méi)有繼續(xù)執(zhí)行,而是等待了,大家是不是感覺(jué)這樣做事很沒(méi)有效率。換言之,如果你在書店買書,老板找一天,你會(huì)持續(xù)等待下去嗎?

接下來(lái)我們談?wù)凟xecutorService這個(gè)接口,它可以表示線程池對(duì)象;當(dāng)線程空閑時(shí),它可以接受一個(gè)提交給ExecutorService的callable對(duì)象,當(dāng)線程結(jié)束的時(shí)候,他會(huì)返回一個(gè)Future.

package com._thread;import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future;/*** 異步編程* @author gosaint**/ public class AsynchronousWorker {public AsynchronousWorker() {}public void doWork() {try {System.out.println("==== 找書, 找書, 找書 ====== ");Thread.sleep(2000);System.out.println("==== OK! ======");} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args) {SlowWorker worker = new SlowWorker();// 主線程模擬買書的人,doWork()方法模擬書店老板的行為!System.out.println("老板,我要買書" + new java.util.Date());// 此時(shí)我們創(chuàng)建一個(gè)線程池,個(gè)數(shù)為3ExecutorService service = Executors.newFixedThreadPool(3);// 此時(shí)存在一個(gè)線程池對(duì)象,線程池對(duì)象提交任務(wù),是一個(gè)callable接口Future<String> future = service.submit(new Callable<String>() {@Overridepublic String call() throws Exception {new AsynchronousWorker().doWork(); return null;}});System.out.println("... 老板在找書的過(guò)程中我可以干些事情嗎!....");System.out.println("做愛(ài)做的事情!");try {//調(diào)用此方法可以獲取我們?nèi)蝿?wù)的執(zhí)行結(jié)果,但是會(huì)阻止主線程的運(yùn)行,直到得到一個(gè)結(jié)果 future.get(); } catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}System.out.println("書買到了" + new java.util.Date());System.exit(0);}}

運(yùn)行結(jié)果如下:

老板,我要買書Sun Jan 21 02:16:13 CST 2018 ... 老板在找書的過(guò)程中我可以干些事情嗎!.... 做愛(ài)做的事情! ==== 找書, 找書, 找書 ====== ==== OK! ====== 書買到了Sun Jan 21 02:16:15 CST 2018

 主線程開(kāi)始運(yùn)行,接著我們向ExecutorService提交了一個(gè)買書的任務(wù),之后我們?cè)诟善渌氖虑椤6詈竽?#xff0c;Future對(duì)象從ExecutorService獲取到了執(zhí)行的結(jié)果。我們調(diào)用get()方法獲取到了執(zhí)行的結(jié)果;倘若我們沒(méi)有這個(gè)調(diào)用,那么還是一個(gè)并行計(jì)算,那么老板找書的結(jié)果不會(huì)立馬給我們返回的; 

轉(zhuǎn)載于:https://www.cnblogs.com/gosaint/p/8320866.html

總結(jié)

以上是生活随笔為你收集整理的线程2---异步1的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。