跳到主要內容

發表文章

目前顯示的是有「Java Design」標籤的文章

Java Lambda - Method Reference

Problem 我有個透過JNA去存取硬體資料的程式: public interface Bus extends Library { Bus INSTANCE = ( Bus ) Native . loadLibrary ( "buslib" , Bus. class ) ;   boolean sendData ( byte bus, byte data [ ] ) ; boolean getData ( byte bus, byte data [ ] ) ; }   public boolean sendData ( byte bus, byte data [ ] ) { synchronized ( Bus. class ) { return Bus. INSTANCE . sendData ( bus, data ) ; } }   public boolean getData ( byte bus, byte data [ ] ) { synchronized ( Bus. class ) { return Bus. INSTANCE . getData ( bus, data ) ; } } 某天有了需要做存取控管需求,因此我在Bus Library介面上增加了兩個methods: boolean lockBus ( byte bus ) ; boolean releaseBus ( byte bus ) ; 而sendData中,在實際請求前會先lockBus,使用後再releaseBus: public boolean sendData ( byte bus, byte data [ ] ) { synchronized ( Bus. class ) { try { boolean ret = false ; if ( ! ( ret = Bus. INSTANCE . lockBus ( bus ) ) ) { return ret ; } return Bus. INSTANCE . sendData...

Java - NotificationBuffer With DelayQueue

Introduction 說到DelayQueue,我會想到拿來與ExecutorService一起使用,用以控制工作延遲多久被執行。為什麼我會把它與NotificationBuffer放在一起呢? 假設某一個Client有可能在短時間內送五筆相同資料過來,目前我們Server是會做五次例行工作;對於最後結果來說,其實我們只需要最後一次即可。除此之外,假如有多個Client,我希望能夠針對各別Client去計算這個時間區間。 Why DelayQueue? 從這兩點來說,我們需要一個buffer來儲存通知資料;然後這個buffer能夠根據各個Client第一次到達的時間,去決定何時讓Server取出並執行例行工作。以這樣的需求來說,DelayQueue是一個不錯的選擇。主要有以下幾個原因: Producer只要把通知資料放進buffer,它就可以回傳了。 繼承自BlockingQueue: 在buffer沒資料時,Consumer thread會處於block。這可以避免不必要的polling。 使用PriorityQueue儲存資料: 這使得通知資料被加入buffer時,delay最短的那筆將會優先被take出去。這減少我們自己寫程式計算這些東西。 根據delay時間去等待: 在每次資料被加入時,它會重新取得最短delay時間並做await。它使用必要的等待去取代不必要的polling檢查。 接下來我將說明要達成我目的的兩個重要物件: NotifiedObject: 通知資料物件。 NotificationBuffer: 儲存通知資料物件的Buffer。 NotifiedObject 要實作自己的delayed物件,必須implements Dealyed介面,而它是extends Comparable介面,因此我們必須要實作compareTo與getDelay;除此之外,這個物件為了達到需求,會記載區別client的id與工作開始時間。可以參考底下程式碼: import java.util.concurrent.Delayed ; import java.util.concurrent.TimeUnit ;   public class NotifiedObject implements Delayed {   privat...

Java Design - 可重複使用的Retry

Why... 當系統發生了例外情況時,夠強健的系統會重新嘗試(retry)發生問題的操作,最常見的例子就是連線中斷的重連。也有可能會另尋其它路徑,像是使用備援的系統或資料來源。一開始我採用了while/for loop的方式做retry,然而當這樣的程式碼夠多後,看了也挺令人厭煩的。Spring有提供RetryTemplate,讓你可以實做想要的Retry。但Spring實在太大包了,除非系統中一定會用到Spring,否則要包這個東西進去,也是挺OOXX的。 I Thinking & Trying 於是我開始嘗試著造輪子。我參考Reference的三篇文章,並設計了一個折中的方式,可以滿足大部分的需求(我需要的需求)。 設定重試次數 設定重試條件 設定重試延遲時間 可做Alternative操作 我參考了Reference中的三篇文章,設計了一個我認為好擴充與方便使用的RetryableTask類別,讓我可以將這些繁瑣的動作給包裝起來: 概念相當簡單: RetryableTask負責執行這些retry的動作,它依賴於Callable、ISleepStrategy、IRetryablePolicy類別。 Callable類別讓Programmer將操作給包裝起來,管你是要從DB還是從檔案取資料,這裡就是提供功能的操作流程。 ISleepStrategy負責讓RetryableTask知道每次Retry時,需要先等待幾秒鐘。目前提供了BasicSleepStrategy(固定時間)與VariableSleepStrategy(變化時間)。 IRetryablePolicy會根據每次操作的結果,決定是否要Retry。這裡使用了Composite Pattern,讓你可以使用多個Policy去控制Retry策略。目前提供了AttemptRetryablePolicy(最大次數)、NullRetryablePolicy(不可為NULL)、ExceptioRetryablePolicy(例外情形)三種策略。 Programming IRetryableTask 首先讓我們看看RetryableTask的member與constructor,預設是使用BasicSleepStrategy與ExceptioRetryablePolicy,當然也可以透過set method去...