成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

多線程開發(fā)的捷徑:構(gòu)建Java并發(fā)模型框架

開發(fā) 后端
本文圍繞一個(gè)簡單的例子論述了如何構(gòu)架一個(gè)Java并發(fā)模型框架,其中使用了一些構(gòu)建框架的常用技術(shù),希望讀者能夠深加領(lǐng)會其原理,也希望您可以對本文中的框架進(jìn)行擴(kuò)充,直接應(yīng)用到自己的工作中。

Java多線程特性為構(gòu)建高性能的應(yīng)用提供了極大的方便,但是也帶來了不少的麻煩。線程間同步、數(shù)據(jù)一致性等煩瑣的問題需要細(xì)心的考慮,一不小心就會出現(xiàn)一些微妙的,難以調(diào)試的錯(cuò)誤。

另外,應(yīng)用邏輯和線程邏輯糾纏在一起,會導(dǎo)致程序的邏輯結(jié)構(gòu)混亂,難以復(fù)用和維護(hù)。本文試圖給出一個(gè)解決這個(gè)問題的方案,通過構(gòu)建一個(gè)并發(fā)模型框架(framework),使得開發(fā)多線程的應(yīng)用變得容易。

基礎(chǔ)知識

Java語言提供了對于線程很好的支持,實(shí)現(xiàn)方法小巧、優(yōu)雅。對于方法重入的保護(hù),信號量(semaphore)和臨界區(qū)(critical section)機(jī)制的實(shí)現(xiàn)都非常簡潔。可以很容易的實(shí)現(xiàn)多線程間的同步操作從而保護(hù)關(guān)鍵數(shù)據(jù)的一致性。這些特點(diǎn)使得Java成為面向?qū)ο笳Z言中對于多線程特性支持方面的佼佼者(C++正在試圖把boost庫中的對于線程的支持部分納入語言標(biāo)準(zhǔn))。

Java中內(nèi)置了對于對象并發(fā)訪問的支持,每一個(gè)對象都有一個(gè)監(jiān)視器(monitor),同時(shí)只允許一個(gè)線程持有監(jiān)視器從而進(jìn)行對對象的訪問,那些沒有獲得監(jiān)視器的線程必須等待直到持有監(jiān)視器的線程釋放監(jiān)視器。對象通過synchronized關(guān)鍵字來聲明線程必須獲得監(jiān)視器才能進(jìn)行對自己的訪問。

synchronized聲明僅僅對于一些較為簡單的線程間同步問題比較有效,對于哪些復(fù)雜的同步問題,比如帶有條件的同步問題,Java提供了另外的解決方法,wait/notify/notifyAll。

獲得對象監(jiān)視器的線程可以通過調(diào)用該對象的wait方法主動釋放監(jiān)視器,等待在該對象的線程等待隊(duì)列上,此時(shí)其他線程可以得到監(jiān)視器從而訪問該對象,之后可以通過調(diào)用notify/notifyAll方法來喚醒先前因調(diào)用wait方法而等待的線程。

一般情況下,對于wait/notify/notifyAll方法的調(diào)用都是根據(jù)一定的條件來進(jìn)行的,比如:經(jīng)典的生產(chǎn)者/消費(fèi)者問題中對于隊(duì)列空、滿的判斷。熟悉POSIX的讀者會發(fā)現(xiàn),使用wait/notify/notifyAll可以很容易的實(shí)現(xiàn)POSIX中的一個(gè)線程間的高級同步技術(shù):條件變量。

簡單例子

本文將圍繞一個(gè)簡單的例子展開論述,這樣可以更容易突出我們解決問題的思路、方法。本文想向讀者展現(xiàn)的正是這些思路、方法。這些思路、方法更加適用于解決大規(guī)模、復(fù)雜應(yīng)用中的并發(fā)問題。考慮一個(gè)簡單的例子,我們有一個(gè)服務(wù)提供者,它通過一個(gè)接口對外提供服務(wù),服務(wù)內(nèi)容非常簡單,就是在標(biāo)準(zhǔn)輸出上打印Hello World。類結(jié)構(gòu)圖如下:

類結(jié)構(gòu)圖

代碼如下:

  1. interface Service  
  2. {  
  3.     public void sayHello();  
  4. }  
  5. class ServiceImp implements Service  
  6. {  
  7.     public void sayHello() {  
  8.         System.out.println("Hello World!");  
  9.     }  
  10. }  
  11. class Client  
  12. {  
  13.     public Client(Service s) {  
  14.         _service = s;  
  15. }      
  16.     public void requestService() {  
  17.         _service.sayHello();  
  18.     }  
  19.     private Service _service;  

如果現(xiàn)在有新的需求,要求該服務(wù)必須支持Client的并發(fā)訪問。一種簡單的方法就是在ServicImp類中的每個(gè)方法前面加上synchronized聲明,來保證自己內(nèi)部數(shù)據(jù)的一致性(當(dāng)然對于本例來說,目前是沒有必要的,因?yàn)镾erviceImp沒有需要保護(hù)的數(shù)據(jù),但是隨著需求的變化,以后可能會有的)。但是這樣做至少會存在以下幾個(gè)問題:

1.現(xiàn)在要維護(hù)ServiceImp的兩個(gè)版本:多線程版本和單線程版本(有些地方,比如其他項(xiàng)目,可能沒有并發(fā)的問題),容易帶來同步更新和正確選擇版本的問題,給維護(hù)帶來麻煩。

2.如果多個(gè)并發(fā)的Client頻繁調(diào)用該服務(wù),由于是直接同步調(diào)用,會造成Client阻塞,降低服務(wù)質(zhì)量。

3.很難進(jìn)行一些靈活的控制,比如:根據(jù)Client的優(yōu)先級進(jìn)行排隊(duì)等等。

4.這些問題對于大型的多線程應(yīng)用服務(wù)器尤為突出,對于一些簡單的應(yīng)用(如本文中的例子)可能根本不用考慮。本文正是要討論這些問題的解決方案,文中的簡單的例子只是提供了一個(gè)說明問題,展示思路、方法的平臺。

5.如何才能較好的解決這些問題,有沒有一個(gè)可以重用的解決方案呢?讓我們先把這些問題放一放,先來談?wù)労涂蚣苡嘘P(guān)的一些問題。

#p#

框架概述

熟悉面向?qū)ο蟮淖x者一定知道面向?qū)ο蟮淖畲蟮膬?yōu)勢之一就是:軟件復(fù)用。通過復(fù)用,可以減少很多的工作量,提高軟件開發(fā)生產(chǎn)率。復(fù)用本身也是分層次的,代碼級的復(fù)用和設(shè)計(jì)架構(gòu)的復(fù)用。

大家可能非常熟悉C語言中的一些標(biāo)準(zhǔn)庫,它們提供了一些通用的功能讓你的程序使用。但是這些標(biāo)準(zhǔn)庫并不能影響你的程序結(jié)構(gòu)和設(shè)計(jì)思路,僅僅是提供一些機(jī)能,幫助你的程序完成工作。它們使你不必重頭編寫一般性的通用功能(比如printf),它們強(qiáng)調(diào)的是程序代碼本身的復(fù)用性,而不是設(shè)計(jì)架構(gòu)的復(fù)用性。

那么什么是框架呢?所謂框架,它不同于一般的標(biāo)準(zhǔn)庫,是指一組緊密關(guān)聯(lián)的(類)classes,強(qiáng)調(diào)彼此的配合以完成某種可以重復(fù)運(yùn)用的設(shè)計(jì)概念。這些類之間以特定的方式合作,彼此不可或缺。它們相當(dāng)程度的影響了你的程序的形貌。框架本身規(guī)劃了應(yīng)用程序的骨干,讓程序遵循一定的流程和動線,展現(xiàn)一定的風(fēng)貌和功能。這樣就使程序員不必費(fèi)力于通用性的功能的繁文縟節(jié),集中精力于專業(yè)領(lǐng)域。

有一點(diǎn)必須要強(qiáng)調(diào),放之四海而皆準(zhǔn)的框架是不存在的,也是最沒有用處的。框架往往都是針對某個(gè)特定應(yīng)用領(lǐng)域的,是在對這個(gè)應(yīng)用領(lǐng)域進(jìn)行深刻理解的基礎(chǔ)上,抽象出該應(yīng)用的概念模型,在這些抽象的概念上搭建的一個(gè)模型,是一個(gè)有形無體的框架。不同的具體應(yīng)用根據(jù)自身的特點(diǎn)對框架中的抽象概念進(jìn)行實(shí)現(xiàn),從而賦予框架生命,完成應(yīng)用的功能。

基于框架的應(yīng)用都有兩部分構(gòu)成:框架部分和特定應(yīng)用部分。要想達(dá)到框架復(fù)用的目標(biāo),必須要做到框架部分和特定應(yīng)用部分的隔離。使用面向?qū)ο蟮囊粋€(gè)強(qiáng)大功能:多態(tài),可以實(shí)現(xiàn)這一點(diǎn)。在框架中完成抽象概念之間的交互、關(guān)聯(lián),把具體的實(shí)現(xiàn)交給特定的應(yīng)用來完成。其中一般都會大量使用了Template Method設(shè)計(jì)模式。Java中的Collection Framework以及微軟的MFC都是框架方面很好的例子。有興趣的讀者可以自行研究。

構(gòu)建框架

如何構(gòu)建一個(gè)Java并發(fā)模型框架呢?讓我們先回到原來的問題,先來分析一下原因。造成要維護(hù)多線程和單線程兩個(gè)版本的原因是由于把應(yīng)用邏輯和并發(fā)邏輯混在一起,如果能夠做到把應(yīng)用邏輯和并發(fā)模型進(jìn)行很好的隔離,那么應(yīng)用邏輯本身就可以很好的被復(fù)用,而且也很容易把并發(fā)邏輯添加進(jìn)來而不會對應(yīng)用邏輯造成任何影響。造成Client阻塞,性能降低以及無法進(jìn)行額外的控制的原因是由于所有的服務(wù)調(diào)用都是同步的,解決方案很簡單,改為異步調(diào)用方式,把服務(wù)的調(diào)用和服務(wù)的執(zhí)行分離。

首先來介紹一個(gè)概念,活動對象(Active Object)。所謂活動對象是相對于被動對象(passive object)而言的,被動對象的方法的調(diào)用和執(zhí)行都是在同一個(gè)線程中的,被動對象方法的調(diào)用是同步的、阻塞的,一般的對象都屬于被動對象;主動對象的方法的調(diào)用和執(zhí)行是分離的,主動對象有自己獨(dú)立的執(zhí)行線程,主動對象的方法的調(diào)用是由其他線程發(fā)起的,但是方法是在自己的線程中執(zhí)行的,主動對象方法的調(diào)用是異步的,非阻塞的。

本框架的核心就是使用主動對象來封裝并發(fā)邏輯,然后把Client的請求轉(zhuǎn)發(fā)給實(shí)際的服務(wù)提供者(應(yīng)用邏輯),這樣無論是Client還是實(shí)際的服務(wù)提供者都不用關(guān)心并發(fā)的存在,不用考慮并發(fā)所帶來的數(shù)據(jù)一致性問題。從而實(shí)現(xiàn)應(yīng)用邏輯和并發(fā)邏輯的隔離,服務(wù)調(diào)用和服務(wù)執(zhí)行的隔離。下面給出關(guān)鍵的實(shí)現(xiàn)細(xì)節(jié)。

本框架有如下幾部分構(gòu)成:

1.一個(gè)ActiveObject類,從Thread繼承,封裝了并發(fā)邏輯的活動對象;

2.一個(gè)ActiveQueue類,主要用來存放調(diào)用者請求;

3.一個(gè)MethodRequest接口,主要用來封裝調(diào)用者的請求,Command設(shè)計(jì)模式的一種實(shí)現(xiàn)方式。它們的一個(gè)簡單的實(shí)現(xiàn)如下:

  1.  //MethodRequest接口定義  
  2.   interface MethodRequest  
  3. {  
  4.     public void call();  
  5. }  
  6. //ActiveQueue定義,其實(shí)就是一個(gè)producer/consumer隊(duì)列  
  7.     class ActiveQueue  
  8. {  
  9.       public ActiveQueue() {  
  10.         _queue = new Stack();  
  11.       }  
  12.     public synchronized void enqueue(MethodRequest mr) {  
  13.         while(_queue.size() > QUEUE_SIZE) {  
  14.             try {  
  15.                    wait();  
  16.             }catch (InterruptedException e) {  
  17.                    e.printStackTrace();  
  18.             }     
  19.         }  
  20.            
  21.         _queue.push(mr);  
  22.         notifyAll();  
  23.         System.out.println("Leave Queue");  
  24.     }  
  25.     public synchronized MethodRequest dequeue() {  
  26.         MethodRequest mr;  
  27.           
  28.         while(_queue.empty()) {  
  29.             try {  
  30.                 wait();  
  31.             }catch (InterruptedException e) {  
  32.                 e.printStackTrace();  
  33.             }  
  34.         }  
  35.         mr = (MethodRequest)_queue.pop();  
  36.         notifyAll();  
  37.           
  38.  return mr;  
  39.     }      
  40.     private Stack _queue;  
  41.     private final static int QUEUE_SIZE = 20;  
  42. }  
  43. //ActiveObject的定義  
  44. class ActiveObject extends Thread  
  45. {  
  46.     public ActiveObject() {  
  47.         _queue = new ActiveQueue();  
  48.         start();  
  49.     }  
  50.     public void enqueue(MethodRequest mr) {  
  51.         _queue.enqueue(mr);  
  52.     }  
  53.     public void run() {  
  54.         while(true) {  
  55.             MethodRequest mr = _queue.dequeue();  
  56.             mr.call();  
  57.         }  
  58.     }   
  59.     private ActiveQueue _queue;  

通過上面的代碼可以看出正是這些類相互合作完成了對并發(fā)邏輯的封裝。開發(fā)者只需要根據(jù)需要實(shí)現(xiàn)MethodRequest接口,另外再定義一個(gè)服務(wù)代理類提供給使用者,在服務(wù)代理者類中把服務(wù)調(diào)用者的請求轉(zhuǎn)化為MethodRequest實(shí)現(xiàn),交給活動對象即可。

使用該框架,可以較好的做到應(yīng)用邏輯和并發(fā)模型的分離,從而使開發(fā)者集中精力于應(yīng)用領(lǐng)域,然后平滑的和并發(fā)模型結(jié)合起來,并且可以針對ActiveQueue定制排隊(duì)機(jī)制,比如基于優(yōu)先級等。

#p#

基于框架的解決方案

本小節(jié)將使用上述的框架重新實(shí)現(xiàn)前面的例子,提供對于并發(fā)的支持。第一步先完成對于MethodRequest的實(shí)現(xiàn),對于我們的例子來說實(shí)現(xiàn)如下:

  1. class SayHello implements MethodRequest  
  2. {  
  3.     public SayHello(Service s) {  
  4.         _service = s;  
  5.     }  
  6.     public void call() {  
  7.         _service.sayHello();  
  8.     }  
  9.     private Service _service;  

該類完成了對于服務(wù)提供接口sayHello方法的封裝。接下來定義一個(gè)服務(wù)代理類,來完成請求的封裝、排隊(duì)功能,當(dāng)然為了做到對Client透明,該類必須實(shí)現(xiàn)Service接口。定義如下:

  1. class ServiceProxy implements Service  
  2. {  
  3.     public ServiceProxy() {  
  4.         _service = new ServiceImp();  
  5.         _active_object = new ActiveObject();  
  6.     }  
  7.       
  8.     public void sayHello() {  
  9.         MethodRequest mr = new SayHello(_service);  
  10.         _active_object.enqueue(mr);  
  11.     }  
  12.     private Service _service;  
  13.     private ActiveObject _active_object;  

其他的類和接口定義不變,下面對比一下并發(fā)邏輯增加前后的服務(wù)調(diào)用的變化,并發(fā)邏輯增加前,對于sayHello服務(wù)的調(diào)用方法:

  1. Service s = new ServiceImp();  
  2. Client c = new Client(s);  
  3. c.requestService(); 

并發(fā)邏輯增加后,對于sayHello服務(wù)的調(diào)用方法:

  1. Service s = new  ServiceProxy();  
  2. Client c = new Client(s);  
  3. c.requestService(); 

可以看出并發(fā)邏輯增加前后對于Client的ServiceImp都無需作任何改變,使用方式也非常一致,ServiceImp也能夠獨(dú)立的進(jìn)行重用。類結(jié)構(gòu)圖如下:

類結(jié)構(gòu)圖

讀者容易看出,使用框架也增加了一些復(fù)雜性,對于一些簡單的應(yīng)用來說可能根本就沒有必要使用本框架。希望讀者能夠根據(jù)自己的實(shí)際情況進(jìn)行判斷。

結(jié)論

本文圍繞一個(gè)簡單的例子論述了如何構(gòu)架一個(gè)Java并發(fā)模型框架,其中使用了一些構(gòu)建框架的常用技術(shù),當(dāng)然所構(gòu)建的框架和一些成熟的商用框架相比,顯得非常稚嫩,比如沒有考慮服務(wù)調(diào)用有返回值的情況,但是其思想方法是一致的,希望讀者能夠深加領(lǐng)會,這樣無論對于構(gòu)建自己的框架還是理解一些其他的框架都是很有幫助的。讀者可以對本文中的框架進(jìn)行擴(kuò)充,直接應(yīng)用到自己的工作中。

優(yōu)點(diǎn):

1.增強(qiáng)了應(yīng)用的并發(fā)性,簡化了同步控制的復(fù)雜性;
2.服務(wù)的請求和服務(wù)的執(zhí)行分離,使得可以對服務(wù)請求排隊(duì),進(jìn)行靈活的控制;
3.應(yīng)用邏輯和并發(fā)模型分離,使得程序結(jié)構(gòu)清晰,易于維護(hù)、重用;
4.可以使開發(fā)者集中精力于應(yīng)用領(lǐng)域。

缺點(diǎn):

1.由于框架所需類的存在,在一定程度上增加了程序的復(fù)雜性;
2.如果應(yīng)用需要過多的活動對象,由于線程切換開銷會造成性能下降;
3.可能會造成調(diào)試?yán)щy。

【編輯推薦】

  1. Java動態(tài)代理機(jī)制綜合分析及擴(kuò)展
  2. 以簡單的方式消除Java冗余
  3. Java中各類Cache機(jī)制實(shí)現(xiàn)解決方案
責(zé)任編輯:王曉東 來源: IBM
相關(guān)推薦

2016-11-30 17:28:02

移動開發(fā)iOSAndroid

2017-11-17 15:57:09

Java多線程并發(fā)模型

2017-02-14 10:00:19

Java開發(fā)Lock

2017-11-22 09:00:00

2023-10-08 09:34:11

Java編程

2023-10-18 15:19:56

2023-06-13 13:39:00

多線程異步編程

2017-12-18 16:33:55

多線程對象模型

2009-03-24 08:56:23

數(shù)據(jù)同步多線程Java

2022-03-31 07:52:01

Java多線程并發(fā)

2015-07-22 09:39:38

IOS多線程同步

2015-07-22 09:51:51

iOS開發(fā)線程

2019-06-03 09:13:11

線程進(jìn)程多線程

2009-05-12 09:54:09

JavaRestCoC

2015-05-13 14:22:44

RedisNoSQL數(shù)據(jù)庫

2009-09-22 17:21:24

線程局部變量

2009-03-12 10:52:43

Java線程多線程

2019-09-26 10:19:27

設(shè)計(jì)電腦Java

2019-07-18 11:08:09

Java并發(fā)框架

2022-10-11 08:00:47

多線程開發(fā)技巧
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 亚洲一区二区三区免费在线观看 | 国产精品久久久久久久久久久免费看 | 国产精品久久久久久久一区二区 | 欧美精品tv | 久久久久久国产免费视网址 | 91亚洲国产成人久久精品网站 | 精品成人免费一区二区在线播放 | 插插宗合网 | 在线视频 亚洲 | 欧美精品久久久久久久久老牛影院 | 久久亚洲国产精品日日av夜夜 | 日韩精品一区二区三区中文在线 | 欧美日韩最新 | av天天爽| 超碰av人人 | 国产999精品久久久久久 | 精品免费| 人碰人操| 亚洲免费视频网址 | 免费日韩av网站 | 天天综合国产 | 国产一级特黄真人毛片 | 欧美精品综合在线 | 欧美日韩亚洲国产综合 | 国产精品99久久久久久动医院 | 欧美一区二区三区在线 | 亚洲www啪成人一区二区麻豆 | 国产精品久久久久久久久久软件 | 国产sm主人调教女m视频 | 国产十日韩十欧美 | 亚洲成人免费 | 国产精品一区二区三 | 在线观看视频你懂得 | jⅰzz亚洲| 成人乱人乱一区二区三区软件 | 亚洲精品乱码久久久久久蜜桃91 | 成人免费观看网站 | 欧美a在线看 | 午夜影院在线观看 | 一区二区三区在线播放 | 中文天堂网 |