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 }