Java併發編程中的設計模式解析(一)

Java併發編程,除了被用於各類Web應用、分佈式系統和大數據系統,構成高併發系統的核心基礎外,其自己也蘊含着大量的設計模式思想在裏面。這一系列文章主要是結合Java源碼,對併發編程中使用到的、實現的各種設計模式作概括總結,以便進一步沉澱對Java併發設計的理解。算法

模板設計模式sql

Thread類中run和start方法,就是一個典型的模板設計模式的實現,即:父類定義算法邏輯代碼,子類實現其細節數據庫

 1 public synchronized void start() {  2         /**
 3  * 線程對象新建後的New狀態,其內部thereadStatus屬性爲0  4          */
 5         if (threadStatus != 0)  6             throw new IllegalThreadStateException();  7 
 8         /* 同時會被添加到一個ThreadGroup */
 9         group.add(this); 10 
11         boolean started = false; 12         //調用JNI方法start0()來啓動線程
13         try { 14  start0(); 15             started = true; 16         } finally { 17         //線程結束以後,再次啓動將拋出異常
18             try { 19                 if (!started) { 20                     group.threadStartFailed(this); 21  } 22             } catch (Throwable ignore) { 23                 /* do nothing. If start0 threw a Throwable then 24  it will be passed up the call stack */
25  } 26  } 27     }

下面以一個例子演示模板模式:編程

public class TemplateMethod { //至關於Thread類的start方法, 用final修飾避免被更改
    public final void print(String message) { System.out.println("-------------"); wrapPrint(message); System.out.println("-------------"); } //至關於Thread的run方法, 用protected修飾限於子類重寫
    protected void wrapPrint(String message) { } public static void main(String[] args) { //經過匿名內部子類, 重寫父類的wrapPrint方法, 從而實現不一樣的輸出模板
        TemplateMethod t1 = new TemplateMethod() { @Override protected void wrapPrint(String message) { System.out.println("111" + message + "111"); } }; t1.print("Hello World!"); TemplateMethod t2 = new TemplateMethod() { @Override protected void wrapPrint(String message) { System.out.println("222" + message + "222"); } }; t2.print("Hello World!"); } }

策略模式設計模式

建立Java多線程中,實現Runnable接口做爲Target並傳入Thread類的構造方法來生成線程對象的過程,就體現了GoF中策略模式的設計思想。下面是一個簡單的示例:安全

首先,仿照Runnable接口的思想,定義一個用於處理數據庫行的接口數據結構

1 /*
2  * RowHandler定義了對數據庫查詢返回結果操做的方法, 具體實現須要 3  * 實現類完成, 相似於Runnable接口 4  */
5 public interface RowHandler<T> { 6  T handle(ResultSet rs); 7 }

而後,仿照Thread方法,定義數據庫查詢的工做類多線程

 1 public class RecordQuery {  2     
 3     private final Connection connection;  4 
 5     public RecordQuery(Connection connection) {  6         this.connection = connection;  7  }  8     //方法中傳入RowHandler的實現類
 9     public <T> T query(RowHandler<T> handler, String sql, Object... params) throws SQLException { 10  PreparedStatement stmt; 11  ResultSet resultSet; 12             stmt = connection.prepareStatement(sql); 13             int index = 1; 14             for (Object param : params) { 15                 stmt.setObject(index++, param); 16  } 17             resultSet = stmt.executeQuery(); 18             //調用實現類的handle方法來處理數據
19             return handler.handle(resultSet); 20  } 21 }

生產者-消費者模式併發

生產者-消費者模式是使用Java併發編程通訊所實現的經典模式之一。該模式是經過隊列這一數據結構來存儲對象元素,由多線程分別充當生產者和消費者,生產者不斷生成元素、消費者不斷消費元素的過程。下面經過代碼來演示:分佈式

實現一個帶有入隊和出隊的隊列

 1 /*
 2  * 經過一個生產者-消費者隊列來講明線程通訊的基本使用方法  3  */
 4 public class EventQueue {  5     //定義一個隊列元素數量, 一旦賦值則不可更改
 6     private final int max;  7     //定義一個空的內部類, 表明存儲元素
 8     static class Event{ }  9     //定義一個不可改的鏈表集合, 做爲隊列載體
10     private final LinkedList<Event> eventQueue = new LinkedList<>(); 11     //若是不指定初始容量, 則容量默認爲10
12     private final static int DEFAULT_MAX_EVENT = 10; 13     //使用自定義容量初始化隊列
14     public EventQueue(int max) { 15         this.max = max; 16  } 17     //若是不指定初始容量, 則容量默認爲10
18     public EventQueue() { 19         this(DEFAULT_MAX_EVENT); 20  } 21     //封裝一個輸出到控制檯的方法
22     private void console(String message) { 23         System.out.printf("%s:%s\n",Thread.currentThread().getName(), message); 24  } 25     //定義入隊方法
26     public void offer(Event event) { 27         //使用鏈表對象做爲鎖, 經過synchronized代碼塊實現同步
28         synchronized(eventQueue) { 29             //在循環中判斷若是隊列已滿, 則調用鎖的wait方法, 使生產者線程阻塞
30             while(eventQueue.size() >= max) { 31                 try { 32                     console(" the queue is full"); 33  eventQueue.wait(); 34                 } catch (InterruptedException e) { 35  e.printStackTrace(); 36  } 37  } 38             console(" the new event is submitted"); 39  eventQueue.addLast(event); 40             //喚醒全部等待中的消費者;注意若是此處使用notify(),可能致使線程不安全
41             this.eventQueue.notifyAll(); 42  } 43  } 44     //定義出隊方法
45     public Event take() { 46         //使用鏈表對象做爲鎖
47         synchronized(eventQueue) { 48             //在循環中判斷若是隊列已空, 則調用鎖的wait方法, 使消費者線程阻塞
49             while(eventQueue.isEmpty()) { 50                 try { 51                     console(" the queue is empty."); 52  eventQueue.wait(); 53                 } catch (InterruptedException e) { 54  e.printStackTrace(); 55  } 56  } 57             Event event = eventQueue.removeFirst(); 58             //喚醒全部等待中的生產者;注意若是此處使用notify(),可能致使線程不安全
59             this.eventQueue.notifyAll(); 60             console(" the event " + event + " is handled/taked."); 61             return event; 62  } 63  } 64 }

驗證該隊列的類

 1 /*
 2  * producer/client pattern  3  */
 4 public class EventClient {  5     
 6     public static void main(String[] args) {  7         //定義不可變隊列實例
 8         final EventQueue eventQueue = new EventQueue();  9         //新建生產者線程, 能夠設置多個
10         new Thread(()->{ 11             while(true) { 12                 eventQueue.offer(new EventQueue.Event()); 13  } 14         }, "producer").start(); 15         //新建消費者線程, 能夠設置多個
16         new Thread(()->{ 17             while(true) { 18  eventQueue.take(); 19                 try { 20                     TimeUnit.MILLISECONDS.sleep(10); 21                 } catch (InterruptedException e) { 22  e.printStackTrace(); 23  } 24  } 25         }, "consumer").start(); 26  } 27 }
相關文章
相關標籤/搜索