天天看點

從demo到支援高并發前言:

前言:

    Java語言作用很大,因有衆多分門雜類的開源架構導緻Javaer關注高并發細節問題偏少,常常被面試或者面試的時候,别人總是問你current的包,但是卻很少人會詢問你,“這段代碼在高并發的情況下,會出現問題?我們應該如何改寫呢?”是以本篇部落格我想從最簡單的demo,到支援高并發場景的,如果覺得過程中有問題問大家賜教。

案例:

   經典多線程并發問題就是生産者消費者問題,以下列子中,我會加入多種條件,而非一個純種的生産者-消費者模式,可能很多人會覺得現在有了concurrent的PKG下的一大堆ArrayBlockQueue,但今天主題是如何優化改進。

demo,非安全的

public class UserAccount {
    private int balance;
    private long maxMoney = 5000000;
    private long minMOney = 1000000;

    public UserAccount(int balance) {
        this.balance = balance;
    }

    public void deposit(int amount) {
        while (balance + amount < maxMoney) {
            balance += amount;
            System.out.printf("存:" + balance);
        }

    }

    public void withdraw(int amount) {

        while (minMOney > balance - amount) {
            balance -= amount;
            System.out.println("取:" + balance);
        }
    }
}
           

第一步: 上面的代碼很明顯會出現并發問題,簡單點我們加入synchronized

public class UserAccount {
    private int balance;
    private long maxMoney = 90000000;
    private long minMOney = 1000000;

    public UserAccount(int balance) {
        this.balance = balance;
    }

    public synchronized void deposit(int amount) {
//        synchronized (this) {
            while (balance + amount < maxMoney) {
                balance += amount;
                System.out.println("存:" + balance);
            }

        }
//    }

    public synchronized void withdraw(int amount) {

        while (minMOney > balance - amount) {
            balance -= amount;
            System.out.println("取:" + balance);
        }
    }
}
           

 第二步:有沒有發現加入關鍵字synchronized後,是并發問題解決了,但是我們鎖的範圍太廣了,不懂得可以看下synchronized的說明。(當兩個并發線程通路同一個對象object中的這個 synchronized(this)同步代碼塊時,一個時間内隻能有一個線程得到執行)

public void deposit(int amount) {
        synchronized (this) {
            while (balance + amount < maxMoney) {
                balance += amount;
                System.out.println("存:" + balance);
            }

        }
    }
           

 第四步:實際過程中,往往我們不會隻有一個條件,這時候使用到ReentrantLock

private final Lock monitor = new ReentrantLock();

    private final Condition low = monitor.newCondition();

    private final Condition high = monitor.newCondition();

    public UserAccount(int balance) {
        this.balance = balance;
    }

    public void deposit(int amount) {
        monitor.lock();
        try {
            while (balance + amount < maxMoney) {
                balance += amount;
                System.out.println("存:" + balance);
            }

            low.signal();
        } finally {
            monitor.unlock();
        }
    }
           

 第五步:鎖更新,加入讀寫鎖ReentrantReadWriteLock

private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void read() {
        lock.readLock().lock();
        System.out.println(balance);
        lock.readLock().unlock();
    }
           

  第六步:使用Atomic原子類   第七步:使用violate  假設你的資源類中violate修飾的變量讀的頻繁程度遠遠大于寫,那麼violate修飾的變量就派上用場。

private volatile int value;

    public int getValue() {
        return value;
    }

    public int increment() {
        synchronized (this) {
            return value++;
        }
    }
           

  第八步 異步處理

CompletableFuture.supplyAsync(() -> {do something();}, taskExecutor);
           

  未完待續...