Java的多線程特性爲構建高性能的應用提供了極大的方便,但是也帶來了很多的麻煩。線程間同步、數據一致性等煩瑣的問題需要細心的考慮,一不當心就會出現一些微妙的,難以調試的錯誤。java
另外。應用邏輯和線程邏輯糾纏在一塊兒。會致使程序的邏輯結構混亂,難以複用和維護。設計模式
本文試圖給出一個解決問題的方案。經過構建一個併發模型框架(framework),使得開發多線程的應用變得easy。多線程
普通狀況下,對於wait/notify/notifyAll方法的調用都是依據必定的條件來進行的。比方:經典的生產者/消費者問題中對於隊列空、滿的推斷。熟悉POSIX的讀者會發現,使用wait/notify/notifyAll可以很是easy的實現POSIX中的一個線程間的高級同步技術:條件變量。架構
類結構圖例如如下:
併發
interface Service { public void sayHello(); } class ServiceImp implements Service { public void sayHello() { System.out.println("Hello World!"); } } class Client { public Client(Service s) { _service = s; } public void requestService() { _service.sayHello(); } private Service _service; }
假設現在有新的需求。要求該服務必須支持Client的併發訪問。框架
一種簡單的方法就是在ServicImp類中的每個方法前面加上synchronized聲明,來保證本身內部數據的一致性(固然對於本例來講。眼下是沒有必要的,因爲ServiceImp沒有需要保護的數據,但是隨着需求的變化。之後可能會有的)。但是這樣作至少會存在下面幾個問題:異步
這些問題對於大型的多線程應用server尤其突出,對於一些簡單的應用(如本文中的樣例)可能根本不用考慮。本文正是要討論這些問題的解決方式。文中的簡單的樣例僅僅是提供了一個說明問題。展現思路、方法的平臺。性能
怎樣才幹較好的解決這些問題,有沒有一個可以重用的解決方式呢?讓咱們先把這些問題放一放,先來談談和框架有關的一些問題。
它們至關程度的影響了你的程序的形貌。框架自己規劃了應用程序的骨幹,讓程序遵循必定的流程和動線。展示必定的風貌和功能。spa
這樣就使程序猿沒必要費力於通用性的功能的繁文縟節,集中精力於專業領域。
有一點必須要強調,放之四海而皆準的框架是不存在的。也是最沒實用處的。框架每每都是針對某個特定應用領域的。是在對這個應用領域進行深入理解的基礎上,抽象出該應用的概念模型。在這些抽象的概念上搭建的一個模型,是一個有形無體的框架。不一樣的詳細應用依據自身的特色對框架中的抽象概念進行實現,從而賦予框架生命。完畢應用的功能。
基於框架的應用都有兩部分構成:框架部分和特定應用部分。要想達到框架複用的目標,必須要作到框架部分和特定應用部分的隔離。線程
使用面向對象的一個強大功能:多態。可以實現這一點。在框架中完畢抽象概念之間的交互、關聯,把詳細的實現交給特定的應用來完畢。
當中通常都會大量使用了Template Method設計模式。
從而實現應用邏輯和併發邏輯的隔離,服務調用和服務運行的隔離。如下給出關鍵的實現細節。
本框架有例如如下幾部分構成:
一個ActiveObject類,從Thread繼承,封裝了併發邏輯的活動對象
一個ActiveQueue類,主要用來存放調用者請求
一個MethodRequest接口,主要用來封裝調用者的請求,Command設計模式的一種實現方式
它們的一個簡單的實現例如如下:
//MethodRequest接口定義 interface MethodRequest { public void call(); } //ActiveQueue定義,事實上就是一個producer/consumer隊列 class ActiveQueue { public ActiveQueue() { _queue = new Stack(); } public synchronized void enqueue(MethodRequest mr) { while(_queue.size() > QUEUE_SIZE) { try { wait(); }catch (InterruptedException e) { e.printStackTrace(); } } _queue.push(mr); notifyAll(); System.out.println("Leave Queue"); } public synchronized MethodRequest dequeue() { MethodRequest mr; while(_queue.empty()) { try { wait(); }catch (InterruptedException e) { e.printStackTrace(); } } mr = (MethodRequest)_queue.pop(); notifyAll(); return mr; } private Stack _queue; private final static int QUEUE_SIZE = 20; } //ActiveObject的定義 class ActiveObject extends Thread { public ActiveObject() { _queue = new ActiveQueue(); start(); } public void enqueue(MethodRequest mr) { _queue.enqueue(mr); } public void run() { while(true) { MethodRequest mr = _queue.dequeue(); mr.call(); } } private ActiveQueue _queue; }
class SayHello implements MethodRequest { public SayHello(Service s) { _service = s; } public void call() { _service.sayHello(); } private Service _service; }該類完畢了對於服務提供接口sayHello方法的封裝。
接下來定義一個服務代理類,來完畢請求的封裝、排隊功能。固然爲了作到對Client透明。該類必須實現Service接口。定義例如如下:
class ServiceProxy implements Service { public ServiceProxy() { _service = new ServiceImp(); _active_object = new ActiveObject(); } public void sayHello() { MethodRequest mr = new SayHello(_service); _active_object.enqueue(mr); } private Service _service; private ActiveObject _active_object; }
Service s = new ServiceImp(); Client c = new Client(s); c.requestService();併發邏輯添加後,對於sayHello服務的調用方法:
Service s = new ServiceImp(); Client c = new Client(s); c.requestService();
但願讀者能夠依據本身的實際狀況進行推斷。
讀者可以對本文中的框架進行擴充,直接應用到本身的工做中。參考文獻〔1〕中對於構建併發模型框架中的很是多細節問題進行了深刻的論述。有興趣的讀者可以自行研究。如下列出本框架的優缺點:
長處:
加強了應用的併發性,簡化了同步控制的複雜性
服務的請求和服務的運行分離,使得可以對服務請求排隊,進行靈活的控制
應用邏輯和併發模型分離,使得程序結構清晰。易於維護、重用
可以使開發人員集中精力於應用領域
缺點: 由於框架所需類的存在,在必定程度上添加了程序的複雜性 假設應用需要過多的活動對象,由於線程切換開銷會形成性能降低 可能會形成調試困難