[hadoop] hadoop性能優化 模擬讀寫分離核心代碼

package com.simulation.core;

import java.util.LinkedList;
import java.util.concurrent.atomic.LongAdder;
/***
AtomicLong的實現原理是:利用底層操作系統的CAS來保證原子性,在一個死循環內不斷執行CAS操作,直到操作成功。不過,CAS操作的一個問題是在併發量比較大的時候,可能很多次的執行CAS操作都不成功,這樣性能就受到較大影響。 
那我們知道,在ConcurrentHashMap中,對Map分割成多個segment,這樣多個Segment的操作就可以並行執行,從而可以提高性能。在JDK8中,LongAdder與ConcurrentHashMap類似,將內部操作數據value分離成一個Cell數組,每個線程訪問時,通過Hash等算法映射到其中一個Cell上。 
計算最終的數據結果,則是各個Cell數組的累計求和。
*/
public class runHadoop {
    /**
     * 測試
     * 1000個線程
     * 刷10000條log
     * */
    public static void main(String[] args) {
        runHadoop run = new runHadoop();
        for(int i = 0;i < 1000;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int j = 0;j < 10000; j++){
                        run.logEdit("日誌");
                    }
                }
            }).start();
        }

    }

    //long taxID = 0L;
    DoubleBuffer doubleBuffer = new DoubleBuffer();
    //每個線程擁有自己的副本
    ThreadLocal<Long> threadLocal = new ThreadLocal<Long>();
    //是否後臺正在把數據同步到磁盤上
    public boolean isSyncRunning = false;
    //正在同步磁盤的內存塊裏面最大的一個ID號
    long maxtaxid = 0L;
    boolean isWait = false;
    LongAdder taxID=new LongAdder();
    /**
     * 寫元數據的核心方法
     * */
    private void logEdit(String log){
        taxID.increment();
        synchronized (this){
            threadLocal.set(taxID.longValue());
            Edlog edlog = new Edlog(taxID.longValue(),log);
            //往內存裏寫東西
            doubleBuffer.write(edlog);
        }//釋放鎖
        //把數據持久化到磁盤

        //重新枷鎖
        logFlush();
    }
    private void logFlush(){
        synchronized(this){
            //多線程同步
            if(isSyncRunning){//false
                //獲取當前事務Id
                long localTaxID = threadLocal.get();
                //2 < 3
                if(localTaxID <= maxtaxid){ //數據是否一樣
                    return;
                }
                if (isWait){    //是否有線程在寫
                    return;
                }
                isWait = true; //標記在寫
                while (isSyncRunning){
                    try{
                        this.wait(1000); //釋放鎖
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
                isWait = false;
            }
            //程序直接走到這
            doubleBuffer.exchange();//交換內存
            //maxTaxid = 3 ;
            if(doubleBuffer.syncBuffer.size() > 0){
                maxtaxid = doubleBuffer.getMaxTaxid();
            }
            isSyncRunning = true;//
        }//釋放鎖
        //數據持久化到磁盤 IO比較慢費性能
        doubleBuffer.flush();
        synchronized(this){
            isSyncRunning = false; //修改標誌位
            this.notifyAll(); //喚醒線程
        }
    }
    /**
     *
     * edLog日誌對象
     */
    class Edlog{

        private long taxID;
        private String log;

        public Edlog(long taxID,String log) {
            this.taxID = taxID;
            this.log = log;
        }

        @Override
        public String toString() {
            return "Edlog{" +
                    "taxID=" + taxID +
                    ", log='" + log + '\'' +
                    '}';
        }
    }

    /**
     * 日誌讀寫過程
     * */
    class DoubleBuffer{

        //寫數據 有序隊列
        LinkedList<Edlog> currentBuffer = new LinkedList<>();
        //持久數據化
        LinkedList<Edlog> syncBuffer = new LinkedList<>();


        /**
         * 寫元數據
         * */
        public void write(Edlog log){
            currentBuffer.add(log);
        }

        /**
         * 持久化到磁盤
         * */
        public void flush(){
            for(Edlog log:syncBuffer){
                System.out.println(log); //模擬打印出來
            }
            syncBuffer.clear(); //釋放內存
        }

        /**
         * 讀寫分離
         * 交換內存
         */
        public void exchange(){
            LinkedList<Edlog> tmp = currentBuffer;
            currentBuffer = syncBuffer;
            syncBuffer = tmp;
        }
        /**
         * 獲取正在同步的內存中最大的事務ID
         * */
        public long getMaxTaxid(){
            return syncBuffer.getLast().taxID;
        }
    }
}

 

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