我所理解的多線程之synchronized

接觸到JAVA以及有很長一段時間了,平時也沒有什麼時間寫博客,現在把平時工作中所做的筆記貼出來供大家參考一下
synchronized關鍵字想必接觸過java多線程的同學都知道,主要作用是對某一特定代碼加鎖,使得同一時間只能由一條線程訪問它。但是這個鎖到底是鎖什麼東西呢?
其實synchronized很簡單,沒必要被多線程這個概念嚇壞了。這個鎖,就是鎖當前被訪問的代碼而已。我舉例說明。
1.方法鎖
方法鎖,顧名思義就是鎖住一個方法,使得同一個實例(不同實例可以同時訪問)同時只能有一條線程訪問它。
    public synchronized void method(){
       //do sth..
    }
這是比較簡單而且容易理解的方式。
2.類鎖
類鎖,一般是針對類中的靜態變量(static)而言,同一個類中,即使是不同的對象也不能同時訪問。
    public  synchronized static void method(){
       // do sth..
    }
在單例模式中經常會用到這種寫法。
3.對象鎖
在實際運用當中,方式1雖然很便捷,但在高併發的環境下,對整個方法加鎖並不是一個理想的方式。如果執行這個方法需要1秒鐘,那麼第1000個訪問這個方法的線程就要等1*1000秒,明顯不能這麼處理。那該如何解決呢?這就要用到對象鎖了,在特定代碼塊對一個對象進行加鎖。
    public void method(obj){
       synchronized (obj){
           //do sth..
       }
    }
很多情況下obj並不會是同一個對象。比如你用hibernate從數據庫中取出一個對象,另一條線程中也通過hibernate取出了這個對象,雖然這兩個對象指向的數據是同一條,但它們對應的hashcode並不是同一個,因此JVM認爲它們不是同一個對象,所以剛剛那條代碼並不能對這條數據成功加鎖。那該如何解決呢?
我們可以通過ConcurrentHashMap來保存這個對象的ID,在代碼中對這個ID加鎖即可。
public class MultiThreadTs {
    private static ConcurrentHashMap<Integer,Object> map=new ConcurrentHashMap<Integer, Object>();
    public void method(){
        try{
            synchronized (setAndGet(對象的ID)){
                //do sth..
            }
        }finally {
            remove(對象的ID);
        }

    }
    private Object setAndGet(Integer id){
        map.putIfAbsent(id,new Object());
        return map.get(id);
    }

    private void remove(Integer id){
        map.remove(id);
    }
}
在上面那段代碼中,我們爲什麼不能直接用synchronized(對象的ID)來加鎖呢?因爲在實際生產環境中,兩個整型對象Integer雖然他們具有相同的值,但它們有可能並不是同一個對象,所以要使用ConcurrentHashMap來確保同一個ID下的對象是相同的,這樣程序才能成功鎖住它。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章