Java在多線程高併發下,該如何做到安全的修改同一個數據(含實際操作)

首先舉一個例子

現在有5個用戶同時訪問業務需要生成5個唯一訂單ID並存入數據庫

這是一個公共的生成ID的類,生成的規則是【當前時間+用於自增的全局變量】(不要在意這個方式的弊端,只是用來舉個栗子~)

在這裏插入圖片描述

我們跑一下試試

![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20190810125807427.png![在這裏插入圖片描述](https://img-blog.csdnimg.cn/2019081012590697.png

可以看到竟然有兩個一模一樣的ID,這是萬萬不能允許發生的情況
爲什麼會發生這種情況呢,是因爲多個線程在同一時間訪問了這個方法,然後修改了這個int變量,上一個線程還沒來得及做完所有操作,int值就被另個線程給修改了

下面講解如何解決問題


基於JVM解決:

1.使用Synchronized解決問題

 public class Test{
 	//創建鎖對象
    static synchronizedTest instance=new synchronizedTest();
    public void test() {
        //省略其他的耗時操作。。。
        //使用同步代碼塊對方法內的代碼進行同步操作,鎖對象爲instance
        synchronized(instance){
           //需要執行的代碼。。。
        }
    }
}
給生成ID的代碼加上同步代碼塊,成功解決問題

在這裏插入圖片描述

使用同步代碼塊的作用是:同一時刻,只有一個線程可以執行該代碼塊

除了第一種方法外,還可以使用第二種方法解決問題

2.使用Lock鎖解決問題

public class LockTest {
    private Lock lock = new ReentrantLock();
 
    //需要參與同步的方法
    private void test(Thread thread){
    	//獲取鎖,如果鎖被暫用則一直等待
        lock.lock();
        try {
            System.out.println("獲得了鎖");
        }catch(Exception e){
        	//打印異常
            e.printStackTrace();
        } finally {
            System.out.println("釋放了鎖");
            //釋放鎖
            lock.unlock();
        }
    }
 
給生成ID的代碼加上Lock鎖,成功解決問題

在這裏插入圖片描述


這兩種方法都是爲了解決同步問題,那麼他們的區別是什麼呢?


這裏提供一個表來方便做對比(來源:https://blog.csdn.net/qq_39521554/article/details/81130442)
類別 synchronized Lock
存在層次 Java的關鍵字,在jvm層面上 是一個類
鎖的釋放 1、以獲取鎖的線程執行完同步代碼,釋放鎖 2、線程執行發生異常,jvm會讓線程釋放鎖 在finally中必須釋放鎖,不然容易造成線程死鎖
鎖的獲取 假設A線程獲得鎖,B線程等待。如果A線程阻塞,B線程會一直等待 分情況而定,Lock有多個鎖獲取的方式,具體下面會說道,大致就是可以嘗試獲得鎖,線程可以不用一直等待
鎖狀態 無法判斷 可以判斷
鎖類型 可重入 不可中斷 非公平 可重入 可判斷 可公平(兩者皆可)
性能 少量同步 大量同步

談談我的看法:

兩者有一個很大的區別就是Synchronized是自動釋放鎖的,而ReentrantLock需要手動通過unlock()釋放,如果沒有處理好就很容易死鎖
其次,ReentrantLock鎖機制要比Synchronized更好一些,比如Synchronized因IO等問題被阻塞了,但是又沒有釋放鎖,其他線程便只能乾巴巴的等着,ReentrantLock有機制可以使線程不無限期等待而Synchronized不可以

兩種同步方式的使用建議:

Synchronized和ReentrantLock在一般情況下沒有什麼區別,但是在非常複雜的同步應用中,請考慮使用ReentrantLock,特別是遇到下面3種需求
1.某個線程在等待一個鎖的控制權的這段時間需要中斷
2.需要分開處理一些wait-notify,ReentrantLock裏面的Condition應用,能夠控制notify哪個線程
3.具有公平鎖功能,每個到來的線程都將排隊等候

下一次說說分佈式的解決方案


這是我通過學習對知識的整理及備忘,本博客的所有內容,僅是自己的一些學習筆記,如有錯誤,歡迎指正。如有侵權,請告知修改。

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