多線程裏面的設計模式

今晚總結一下關於開發中常用的多線程設計模式。

Future設計模式

future相信大家對這個東西都不陌生,那麼我們就開門見山的來講吧。
首先來思考幾個問題
future是用來做什麼的?
當我們做一些計算機串行化計算的時候,在等待響應的過程中,接收方的線程是處於堵塞狀態的,比較浪費資源。
這個時候如果採用future來幫我們異步接收參數,避免同步等待的問題,那麼這種方式我們稱之爲future。
future比較常用功能的方式是futuretask,案例如下:

public static void main(String[] args) throws InterruptedException, ExecutionException {
        FutureTask<String> futureTask=new FutureTask<String>(new RealData("*"));
        ExecutorService executorService= Executors.newFixedThreadPool(1);
        executorService.submit(futureTask);
        System.out.println("請求完畢了");
        Thread.sleep(200);
        System.out.println("真實數據"+futureTask.get());
    }

這段代碼在工作中如果有需要可以拿去使用。

如何自己來實現一個future的模型?
future的實現實際上離不開兩個東西,一個是futuredata,就是用於get真實數據的一個引用句柄,還有一個就是realdata,真實響應數據。
由於獲取真實數據的過程可能會比較耗時,所以通常的做法是在異步線程中去獲取響應的數據。
案例代碼如下:
首先定義一個用於給future執行的task

/**
 * @author idea
 * @data 2020/2/15
 */
public interface CallableTask<T> {
    T run();
}

然後是futureData

/**
 * @author idea
 * @data 2020/2/15
 */
public class FutureData {
    private RealData realData;
    private boolean isReady=false;
    public synchronized  void setCallableTask(CallableTask callableTask){
        realData=new RealData(callableTask);
        isReady=false;
        notifyAll();
    }
    public synchronized Object get() throws InterruptedException {
        while (!isReady){
            wait();
        }
        return realData.getResult();
    }
}

接下來是真實接收參數的RealData

/**
 * @author idea
 * @data 2020/2/15
 */
public class RealData {
    private CallableTask callableTask;
    private Object result;
    public RealData(CallableTask callableTask) {
        this.callableTask = callableTask;
        this.result = callableTask.run();
    }
    public Object getResult() {
        return result;
    }
}

接下來便是client客戶端

/**
 * @author idea
 * @data 2020/2/15
 */
public class Client {
    private FutureData futureData;
    public void request(CallableTask callableTask){
        futureData=new FutureData();
        futureData.setCallableTask(callableTask);
    }
    public Object get() throws InterruptedException {
        if(futureData==null){
            throw new RuntimeException("futureData can not be null!");
        }
        return futureData.get();
    }
    static class job implements CallableTask<String>{
        @Override
        public String run() {
            System.out.println("this is run");
            return "ten";
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Client client=new Client();
        client.request(new job());
        for(int i=0;i<10;i++){
            Thread.sleep(10);
            System.out.println("=======");
        }
        Object result = client.get();
        System.out.println(result);
    }
}

最後執行client裏面的main方法便可以驗證了。
根據這樣的案例,相信你也可以看懂future是怎麼運作的了。但是在實際的jdk實現中,future的設計要比這個複雜很多,所以這裏就不做具體的講解了。

Master-Worker模型
如果有接觸過大數據的同學,應該就會對這種模式比較熟悉,常見的hadoop就是基於這種模式設計的。
Master-Worker模式是常用的並行模式之一,它的核心思想是:系統由兩類進程協同工作,即Master進程和Worker進程,Master負責接收和分配任務,Wroker負責處理子任務。當各個Worker進程將子任務處理完成後,將結果返回給Master進程,由Master進程進行彙總,從而得到最終的結果,其具體處理過程如下圖所示。

在這裏插入圖片描述
Master進程爲主要進程,它維護一個Worker進程隊列、子任務隊列和子結果集。Worker進程隊列中的Worker進程不停從任務隊列中提取要處理的子任務,並將結果寫入結果集。
這裏我寫了一個簡單版的master-worker模型供大家學習:
首先是Master

import 重溫_Java併發基礎.並行程序的設計模式.code.master_worker.Worker;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
/**
 * @author idea
 * @data 2020/2/15
 */
public class Master {
    protected Queue<Object> workerQueue = new ConcurrentLinkedDeque<>();
    protected Map<String, Thread> threadMap = new HashMap<>();
    protected Map<String, Object> resultMap = new ConcurrentHashMap<>();
    public Master(Worker worker, int countWorker){
        worker.setWorkerQueue(workerQueue);
        worker.setResultMap(resultMap);
        for(int i=0;i<countWorker;i++){
            threadMap.put(Integer.toString(i),new Thread(worker,"worker"+i));
        }
    }
    public boolean isComplete(){
        for(String key:threadMap.keySet()){
            if(threadMap.get(key).getState()!=Thread.State.TERMINATED){
                return false;
            }
        }
        return true;
    }
    public void submit(Object job){
        workerQueue.add(job);
    }
    /**
     * 執行任務
     */
    public void execute(){
        for (Map.Entry<String,Thread> stringThreadEntry : threadMap.entrySet()) {
            stringThreadEntry.getValue().start();
        }
    }
}

master主要是負責工作的分發和結果的合併
接下來是worker部分的設計:

import java.util.Map;
import java.util.Queue;
import java.util.Set;
/**
 * @author idea
 * @data 2020/2/15
 */
public class Worker implements Runnable {
    protected Queue<Object> workerQueue;
    protected Map<String, Object> resultMap;
    public Worker setWorkerQueue(Queue<Object> workerQueue) {
        this.workerQueue = workerQueue;
        return this;
    }
    public Worker setResultMap(Map<String, Object> resultMap) {
        this.resultMap = resultMap;
        return this;
    }
    public Object handle(Object input) throws InterruptedException {
        return input;
    }
    @Override
    public void run() {
        while (true) {
            Object input = workerQueue.poll();
            if (input == null) {
                break;
            }
            Object result = null;
            try {
                result = handle(input);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            resultMap.put(String.valueOf(result.hashCode()), result);
        }
    }
    private  void  handle_1(){
        Master master = new Master(new PlusWorker(), 10);
        for (int i = 1; i <= 100; i++) {
            master.submit(i);
        }
        int result = 0;
        master.execute();
        Map<String, Object> resultMap = master.resultMap;
        while (resultMap.size() != 0 || !master.isComplete()) {
            Set<String> keySet = resultMap.keySet();
            String key = null;
            for (String s : keySet) {
                key = s;
                break;
            }
            Integer i = null;
            if (key != null) {
                i = (Integer) resultMap.get(key);
            }
            if (i != null) {
                result += i;
            }
            if (key != null) {
                resultMap.remove(key);
            }
        }
        System.out.println(result);
    }
    //計算1+2+3+4+***+10000
    public static void main(String[] args) {
        Worker w=new Worker();
        w.handle_1();
    }
}

給worker設計一個PlusWorker

/**
 * @author idea
 * @data 2020/2/15
 */
public class PlusWorker extends Worker{
    @Override
    public Object handle(Object input) throws InterruptedException {
        Integer val= (Integer) input;
        Thread.sleep(1000);
        return val;
    }
}

此時一個基本的模型也就完成了。

本文完。轉載請註明出處。
參考文獻
葛一鳴,Java程序性能優化.清華大學出版社.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章