电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

Java異步調用轉同步的方法

瀏覽:44日期:2022-08-19 08:46:41

先來說一下對異步和同步的理解:

同步調用:調用方在調用過程中,持續等待返回結果。異步調用:調用方在調用過程中,不直接等待返回結果,而是執行其他任務,結果返回形式通常為回調函數。

其實,兩者的區別還是很明顯的,這里也不再細說,我們主要來說一下Java如何將異步調用轉為同步。換句話說,就是需要在異步調用過程中,持續阻塞至獲得調用結果。不賣關子,先列出五種方法,然后一一舉例說明:

使用wait和notify方法 使用條件鎖 Future 使用CountDownLatch 使用CyclicBarrier 1.構造一個異步調用

首先,寫demo需要先寫基礎設施,這里的話主要是需要構造一個異步調用模型。異步調用類:

public class AsyncCall { private Random random = new Random(System.currentTimeMillis()); private ExecutorService tp = Executors.newSingleThreadExecutor(); //demo1,2,4,5調用方法 public void call(BaseDemo demo){ new Thread(()->{ long res = random.nextInt(10); try {Thread.sleep(res*1000); } catch (InterruptedException e) {e.printStackTrace(); } demo.callback(res); }).start(); } //demo3調用方法 public Future<Long> futureCall(){ return tp.submit(()-> { long res = random.nextInt(10); try {Thread.sleep(res*1000); } catch (InterruptedException e) {e.printStackTrace(); } return res; }); } public void shutdown(){ tp.shutdown(); }}

我們主要關心call方法,這個方法接收了一個demo參數,并且開啟了一個線程,在線程中執行具體的任務,并利用demo的callback方法進行回調函數的調用。大家注意到了這里的返回結果就是一個[0,10)的長整型,并且結果是幾,就讓線程sleep多久——這主要是為了更好地觀察實驗結果,模擬異步調用過程中的處理時間。至于futureCall和shutdown方法,以及線程池tp都是為了demo3利用Future來實現做準備的。demo的基類:

public abstract class BaseDemo { protected AsyncCall asyncCall = new AsyncCall(); public abstract void callback(long response); public void call(){ System.out.println('發起調用'); asyncCall.call(this); System.out.println('調用返回'); }}

BaseDemo非常簡單,里面包含一個異步調用類的實例,另外有一個call方法用于發起異步調用,當然還有一個抽象方法callback需要每個demo去實現的——主要在回調中進行相應的處理來達到異步調用轉同步的目的。

2. 使用wait和notify方法

這個方法其實是利用了鎖機制,直接貼代碼:

public class Demo1 extends BaseDemo{ private final Object lock = new Object(); @Override public void callback(long response) { System.out.println('得到結果'); System.out.println(response); System.out.println('調用結束'); synchronized (lock) { lock.notifyAll(); } } public static void main(String[] args) { Demo1 demo1 = new Demo1(); demo1.call(); synchronized (demo1.lock){ try {demo1.lock.wait(); } catch (InterruptedException e) {e.printStackTrace(); } } System.out.println('主線程內容'); }}

可以看到在發起調用后,主線程利用wait進行阻塞,等待回調中調用notify或者notifyAll方法來進行喚醒。注意,和大家認知的一樣,這里wait和notify都是需要先獲得對象的鎖的。在主線程中最后我們打印了一個內容,這也是用來驗證實驗結果的,如果沒有wait和notify,主線程內容會緊隨調用內容立刻打??;而像我們上面的代碼,主線程內容會一直等待回調函數調用結束才會進行打印。沒有使用同步操作的情況下,打印結果:

發起調用調用返回主線程內容得到結果1調用結束

而使用了同步操作后:

發起調用調用返回得到結果9調用結束主線程內容3. 使用條件鎖

和方法一的原理類似:

public class Demo2 extends BaseDemo { private final Lock lock = new ReentrantLock(); private final Condition con = lock.newCondition(); @Override public void callback(long response) { System.out.println('得到結果'); System.out.println(response); System.out.println('調用結束'); lock.lock(); try { con.signal(); }finally { lock.unlock(); } } public static void main(String[] args) { Demo2 demo2 = new Demo2(); demo2.call(); demo2.lock.lock(); try { demo2.con.await(); } catch (InterruptedException e) { e.printStackTrace(); }finally { demo2.lock.unlock(); } System.out.println('主線程內容'); }}

基本上和方法一沒什么區別,只是這里使用了條件鎖,兩者的鎖機制有所不同。

4. Future

使用Future的方法和之前不太一樣,我們調用的異步方法也不一樣。

public class Demo3{ private AsyncCall asyncCall = new AsyncCall(); public Future<Long> call(){ Future<Long> future = asyncCall.futureCall(); asyncCall.shutdown(); return future; } public static void main(String[] args) { Demo3 demo3 = new Demo3(); System.out.println('發起調用'); Future<Long> future = demo3.call(); System.out.println('返回結果'); while (!future.isDone() && !future.isCancelled()); try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println('主線程內容'); }}

我們調用futureCall方法,方法中會想線程池tp提交一個Callable,然后返回一個Future,這個Future就是我們demo3中call中得到的,得到future對象之后就可以關閉線程池啦,調用asyncCall的shutdown方法。關于關閉線程池這里有一點需要注意,我們回過頭來看看asyncCall的shutdown方法:

public void shutdown(){ tp.shutdown(); }

發現只是簡單調用了線程池的shutdown方法,然后我們說注意的點,這里最好不要用tp的shutdownNow方法,該方法會試圖去中斷線程中中正在執行的任務;也就是說,如果使用該方法,有可能我們的future所對應的任務將被中斷,無法得到執行結果。然后我們關注主線程中的內容,主線程的阻塞由我們自己來實現,通過future的isDone和isCancelled來判斷執行狀態,一直到執行完成或被取消。隨后,我們打印get到的結果。

5. 使用CountDownLatch

使用CountDownLatch或許是日常編程中最常見的一種了,也感覺是相對優雅的一種:

public class Demo4 extends BaseDemo{ private final CountDownLatch countDownLatch = new CountDownLatch(1); @Override public void callback(long response) { System.out.println('得到結果'); System.out.println(response); System.out.println('調用結束'); countDownLatch.countDown(); } public static void main(String[] args) { Demo4 demo4 = new Demo4(); demo4.call(); try { demo4.countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println('主線程內容'); }}

正如大家平時使用的那樣,此處在主線程中利用CountDownLatch的await方法進行阻塞,在回調中利用countDown方法來使得其他線程await的部分得以繼續運行。當然,這里和demo1和demo2中都一樣,主線程中阻塞的部分,都可以設置一個超時時間,超時后可以不再阻塞。

6. 使用CyclicBarrier

CyclicBarrier的情況和CountDownLatch有些類似:

public class Demo5 extends BaseDemo{ private CyclicBarrier cyclicBarrier = new CyclicBarrier(2); @Override public void callback(long response) { System.out.println('得到結果'); System.out.println(response); System.out.println('調用結束'); try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } public static void main(String[] args) { Demo5 demo5 = new Demo5(); demo5.call(); try { demo5.cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println('主線程內容'); }}

大家注意一下,CyclicBarrier和CountDownLatch僅僅只是類似,兩者還是有一定區別的。比如,一個可以理解為做加法,等到加到這個數字后一起運行;一個則是減法,減到0繼續運行。一個是可以重復計數的;另一個不可以等等等等。另外,使用CyclicBarrier的時候要注意兩點。第一點,初始化的時候,參數數字要設為2,因為異步調用這里是一個線程,而主線程是一個線程,兩個線程都await的時候才能繼續執行,這也是和CountDownLatch區別的部分。第二點,也是關于初始化參數的數值的,和這里的demo無關,在平時編程的時候,需要比較小心,如果這個數值設置得很大,比線程池中的線程數都大,那么就很容易引起死鎖了。

總結

綜上,就是本次需要說的幾種方法了。事實上,所有的方法都是同一個原理,也就是在調用的線程中進行阻塞等待結果,而在回調中函數中進行阻塞狀態的解除。

以上就是Java異步調用轉同步的方法的詳細內容,更多關于Java異步調用轉同步的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
主站蜘蛛池模板: 广州二手电缆线回收,旧电缆回收,广州铜线回收-广东益福电缆线回收公司 | 水篦子|雨篦子|镀锌格栅雨水篦子|不锈钢排水篦子|地下车库水箅子—安平县云航丝网制品厂 | 旋振筛|圆形摇摆筛|直线振动筛|滚筒筛|压榨机|河南天众机械设备有限公司 | 钢结构-钢结构厂房-钢结构工程[江苏海逵钢构厂] | PAS糖原染色-CBA流式多因子-明胶酶谱MMP-上海研谨生物科技有限公司 | 南京种植牙医院【官方挂号】_南京治疗种植牙医院那个好_南京看种植牙哪里好_南京茀莱堡口腔医院 尼龙PA610树脂,尼龙PA612树脂,尼龙PA1010树脂,透明尼龙-谷骐科技【官网】 | 武汉高低温试验机-现货恒温恒湿试验箱-高低温湿热交变箱价格-湖北高天试验设备 | 土壤养分检测仪_肥料养分检测仪_土壤水分检测仪-山东莱恩德仪器 大型多片锯,圆木多片锯,方木多片锯,板材多片锯-祥富机械有限公司 | 周口市风机厂,周鼓风机,河南省周口市风机厂 | 14米地磅厂家价价格,150吨地磅厂家价格-百科| 算命免费_生辰八字_免费在线算命 - 卜算子算命网 | Dataforth隔离信号调理模块-信号放大模块-加速度振动传感器-北京康泰电子有限公司 | 定制/定做冲锋衣厂家/公司-订做/订制冲锋衣价格/费用-北京圣达信 | 喷码机,激光喷码打码机,鸡蛋打码机,手持打码机,自动喷码机,一物一码防伪溯源-恒欣瑞达有限公司 | IP检测-检测您的IP质量| 电磁流量计厂家_涡街流量计厂家_热式气体流量计-青天伟业仪器仪表有限公司 | 贴片电感_贴片功率电感_贴片绕线电感_深圳市百斯特电子有限公司 贴片电容代理-三星电容-村田电容-风华电容-国巨电容-深圳市昂洋科技有限公司 | 雪花制冰机(实验室雪花制冰机)百科| 精密交叉滚子轴承厂家,转盘轴承,YRT转台轴承-洛阳千协轴承 | 企典软件一站式企业管理平台,可私有、本地化部署!在线CRM客户关系管理系统|移动办公OA管理系统|HR人事管理系统|人力 | 蓝牙音频分析仪-多功能-四通道-八通道音频分析仪-东莞市奥普新音频技术有限公司 | 免费网站网址收录网_海企优网站推荐平台| 宏源科技-房地产售楼系统|线上开盘系统|售楼管理系统|线上开盘软件 | 智能汉显全自动量热仪_微机全自动胶质层指数测定仪-鹤壁市科达仪器仪表有限公司 | 仿古瓦,仿古金属瓦,铝瓦,铜瓦,铝合金瓦-西安东申景观艺术工程有限公司 | 天津仓储物流-天津电商云仓-天津云仓一件代发-博程云仓官网 | 对辊破碎机-液压双辊式,强力双齿辊,四辊破碎机价格_巩义市金联机械设备生产厂家 | 沈阳缠绕膜价格_沈阳拉伸膜厂家_沈阳缠绕膜厂家直销 | 温州富欧金属封头-不锈钢封头厂家 | 不锈钢水管-不锈钢燃气管-卫生级不锈钢管件-不锈钢食品级水管-广东双兴新材料集团有限公司 | 水质监测站_水质在线分析仪_水质自动监测系统_多参数水质在线监测仪_水质传感器-山东万象环境科技有限公司 | SDG吸附剂,SDG酸气吸附剂,干式酸性气体吸收剂生产厂家,超过20年生产使用经验。 - 富莱尔环保设备公司(原名天津市武清县环保设备厂) | 济南品牌包装设计公司_济南VI标志设计公司_山东锐尚文化传播 | 英语词典_成语词典_日语词典_法语词典_在线词典网 | 宝宝药浴-产后药浴-药浴加盟-艾裕-专注母婴调养泡浴 | 振动时效_振动时效仪_超声波冲击设备-济南驰奥机电设备有限公司 北京宣传片拍摄_产品宣传片拍摄_宣传片制作公司-现像传媒 | 信阳网站建设专家-信阳时代网联-【信阳网站建设百度推广优质服务提供商】信阳网站建设|信阳网络公司|信阳网络营销推广 | 济南律师,济南法律咨询,山东法律顾问-山东沃德律师事务所 | 微水泥_硅藻泥_艺术涂料_艺术漆_艺术漆加盟-青岛泥之韵环保壁材 武汉EPS线条_EPS装饰线条_EPS构件_湖北博欧EPS线条厂家 | 锂电池生产厂家-电动自行车航模无人机锂电池定制-世豹新能源 | 地埋式垃圾站厂家【佳星环保】小区压缩垃圾中转站转运站 |