Future模式
/** * Future模式:是並行模式屬於設計優化的一部分,是對一些常用的多線程結構的總結和抽象。 * 與串行程序相比,並行程序的結構通常更爲複雜,因此合理的使用並行模式在多線程開發中更具有意義。 * 這個模式類似在發送ajax請求,頁面是異步的進行後臺處理,用戶無須一直等待結構就可以繼續瀏覽和進行其他操作。 */ public class C03Future { public static void main(String[] args) throws InterruptedException { Client client = new Client(); String data = client.getData("123"); System.out.println(data); } } class Client {
public String getData(String query) throws InterruptedException { //獲取到代理對象 ProxyData proxyData = new ProxyData();
//偷偷起個線程去加載數據 new Thread(new Runnable() { @Override public void run() { System.out.println("開始加載數據"); HandlerData handlerData = null; try { handlerData = new HandlerData(query);
//設置加載好的數據給代理對象 System.out.println("數據加載完成"); proxyData.setHandlerData(handlerData); } catch (InterruptedException e) { e.printStackTrace(); } } }).start();
System.out.println("返回代理對象");
return proxyData.getHandlerData(); }
} /** * 數據代理 */ class ProxyData {
private HandlerData handlerData;
private boolean isReady = false;
/** * 設置數據,如果數據已有就直接返回,沒有數據就進行處理。 * 假設:數據處理過程需要耗時N秒,用戶在get時,就節省了部分過程的時間。 */ public synchronized void setHandlerData(HandlerData handlerData) { //數據已經準備好了,直接返回 if (isReady) { System.out.println(isReady + ":數據未準備好"); return ; } //數據沒有準備好,開始進行數據處理 this.handlerData = handlerData; isReady = true;
System.out.println("代理對象設置數據成功,喚醒getHandlerData的等待。"); //喚醒通知 notify(); }
/** * 獲取數據 */ public synchronized String getHandlerData() throws InterruptedException { //如果數據沒有處理好,則等待處理 while (!isReady) { System.out.println(isReady + ":數據未準備好,getHandlerData 進入等待"); wait(); }
//返回裝好的數據 return this.handlerData.getResult(); } } /** * 真實的數據 */ class HandlerData { /** * 數據結果 */ private String result;
/** * 模擬數據處理過程 */ public HandlerData(String query) throws InterruptedException { System.out.println("模擬-數據查詢");
//數據處理 Thread.sleep(5000);
System.out.println("模擬-數據處理完成"); result = "end"; }
public String getResult() { return result; } } |
public class C03Future01 { public static void main(String[] args) throws InterruptedException, ExecutionException {
//JDK自帶Api ========================================== String query = "select * from user;";
//構建FutureTask,並且傳入需要真正進行業務處理和實現了Callable接口的類 FutureTask<String> futureTask1 = new FutureTask<String>(new FutureTestClass(query)); FutureTask<String> futureTask2 = new FutureTask<String>(new FutureTestClass(query));
//創建一個固定線程的線程池 ExecutorService pool = Executors.newFixedThreadPool(1);
//提交任務,則開啓線程執行call方法 //submit()和execute()方法的區別,可以看線程池篇的文章 Future submit1 = pool.submit(futureTask1); Future submit2 = pool.submit(futureTask2);
System.out.println("Main線程處理別的業務邏輯"); Thread.sleep(2000);
System.out.println(futureTask1.get()); System.out.println(futureTask2.get());
pool.shutdown(); } } /** * 必須要實現Callable接口 */ class FutureTestClass implements Callable<String> {
private String query;
public FutureTestClass(String query) { super(); this.query = query; }
@Override public String call() throws Exception { Thread.sleep(3000); String result = query + ":處理完成"; return result; } } |
Master-Worker模式
/** * Master-Wroker模式:這也是常用的並行模式,核心思想是系統由Master和Worker兩類進行協同工作。 * Master負責接收和分配任務,Worker負責處理子任務,但各個Worker子進程處理完成後,會將結果返回給Master,由Master歸納和總結。 * 好處就是能將一個大任務分解成爲若干個小任務並行執行,從而提高系統的吞吐量。 * 現有框架設計:Hadoop、Spark */ public class C04MasterWorker { public static void main(String[] args) {
//設置N個Worker同時執行 Master master = new Master(100);
//提交100個任務給master for (int i = 0; i < 100; i++) { master.submitTask(new Task(i,i + " " + "Test")); }
//開始執行 master.execute();
long startTime = System.currentTimeMillis();
while (true) { if(master.isComplete()) { long endTime = System.currentTimeMillis(); System.out.println("結果:" + master.getResult().size()); System.out.println("運行時間:" + (endTime - startTime)); break; } }
/* * 1、Master在初始化時,就生成好對應數量的Worker了,並放在容器中。 * 1.1、Worker會有Master的Task併發存儲容器的引用和併發結果容器存放的引用,讓Worker可以獲取到任務和存放執行結果。 * 2、在提交Task時,由於Worker是併發執行的,所以每一個Task也是存放在併發容器中的。 * 3、調用Master執行方法時,則取出Worker容器中的每一個Worker,啓動該線程去執行任務。 * 3.1、每一個Worker線程會取出Master的Task併發存儲容器中的Task去執行,執行完一個則取出下一個,取的方法是取出後在容器刪除這個Task,避免重複執行。 */
} } /** * 負責接收和分配任務,並收集所有Worker處理的結果 */ class Master {
//存放任務容器 private ConcurrentLinkedQueue<Task> workerTasks = new ConcurrentLinkedQueue<>();
//存放執行的Worker(併發執行) private Map<String, Thread> workers = new HashMap<>();
//存放Worker執行結果(併發執行) private ConcurrentHashMap<String, Object> result = new ConcurrentHashMap<>();
/** * 初始化Master時,也初始化出對應數量的Worker。 * @param worker Worker * @param workerCount */ public Master(int workerCount) { //將容器引用設置過去給Worker Worker worker = new Worker(); worker.setWorkerTasks(workerTasks); worker.setResult(result);
for (int i = 0; i < workerCount; i++) { this.workers.put(i + "", new Thread(worker)); } }
/** * 初始化完成對應的Worker之後,要能讓用戶提交Task,在將Task分配給對應的Worker去執行 * @param task * @return boolean */ public boolean submitTask(Task task) { return this.workerTasks.add(task); }
/** * 提交完成任務後,要讓Workers去執行任務 * @return boolean */ public boolean execute() { for (Entry<String, Thread> entry : workers.entrySet()) { entry.getValue().start(); } return true; }
/** * 所有任務是否已經運行完成 * @return boolean */ public boolean isComplete() { for (Entry<String, Thread> entry : workers.entrySet()) { if (entry.getValue().getState() != Thread.State.TERMINATED) { return false; } } return true; }
/** * 獲取到執行結果 * @return List<Object> */ public List<Object> getResult() { List<Object> result = new ArrayList<>(); for (Entry<String, Object> entry : this.result.entrySet()) { result.add(entry.getValue()); } return result; }
} /** * 具體處理任務 */ class Worker implements Runnable {
//Master分配過來,要執行的任務 private ConcurrentLinkedQueue<Task> workerTasks;
//執行的結果 private ConcurrentHashMap<String, Object> result;
public void setWorkerTasks(ConcurrentLinkedQueue<Task> workerTasks) { this.workerTasks = workerTasks; }
public void setResult(ConcurrentHashMap<String, Object> result) { this.result = result; }
/* * 多線程執行分配到的任務 */ @Override public void run() { while (true) { Task task = this.workerTasks.poll(); if (null == task) { break; } //任務處理,並把處理結果放到容器中 Object handleResult = handle(task); this.result.put(task.getId().toString(), handleResult); } }
/** * 模擬任務處理邏輯 */ private Object handle(Task task) { try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } String desc = task.getDesc(); return desc; }
} /** * 任務 */ class Task {
private Integer id;
private String desc;
public Task(Integer id, String desc) { super(); this.id = id; this.desc = desc; }
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getDesc() { return desc; }
public void setDesc(String desc) { this.desc = desc; } } |