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;
}
}
}