国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

淺談Java中的同步

YacaToy / 564人閱讀

摘要:在多線程的問題上面概念比較多,也需要慢慢理解,其實也在多線程的鎖的上面做了很多優化,還有互斥同步和非互斥同步,還有很多概念,什么是自旋和自適應自旋,鎖消除順便提一下,上面的字符串拼接的例子就是用到了這種優化方式,鎖粗化,我們下次再繼續分享。

在我們平常的開發工作中,或多或少的都能接觸到多線程編程或者一些并發問題,隨著操作系統和系統硬件的升級,并發編程被越來越多的運用到我們的開發中,我們使用多線程的最初的想法是能夠更大程度的利用系統資源,但是我們在使用多線程的時候,也會有一些問題的存在,我們先來看一段代碼。

    private static int i = 0;

    private static void increse(){
        i++;
    }

    public static void main(String[] args) {
    Thread[] threads = new Thread[20];
        for (int i = 0; i < threads.length; i++){
            threads[i] = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 10000; j++){
                        increse();
                    }
                }
            });
            threads[i].start();
        }
        
        while (Thread.activeCount() > 1){
            Thread.yield();
        }
        
        System.out.println(i);
    }

首先看看這段代碼是沒有問題的,但是如果在多線程的環境中,這段代碼運行的結果基本是都不一樣的,這里是開啟20個線程,然后每一個線程調用increse()方法對變量i進行一個賦值操作,預期的一個輸出應該是200000,但是為什么會每一次的輸出都不太一樣呢?原因就在于這個地方i++,這里就是產生并發問題的根本原因,那看起來很簡單的一個i++為什么會有這種問題?這里就簡單的從java內存模型(JMM)來了解一下,首先JMM規定,每一個線程運行時都會有一個工作內存,然后變量i是存儲在主內存的,每次線程在計算數據的時候都要去主內存中獲取當前變量的值,那么簡單的來說,就是一個線程將變量i計算得到結果后,還沒有將這個數據刷新到主內存,在這個時候,其他的線程已經獲取到了原來的值,換句話說,本線程中獲取到的數據是否是最新的,這個是不知道的。但是這只是從JMM角度來簡單的說一下,i++這個看似簡單的操作其實包含了三個操作,獲取i的值,對i進行自增,然后對i進行賦值。就是在這幾個操作中,其他的線程會有很多的時間來做很多的事情,那有人會問,是不是將這個i++操作同步就可以了?是的,那該如何同步呢?

有人說用volatile來修飾一下變量i不就可以了么?是的,javavolatile這個關鍵字確實是提供了一個同步的功能,但是為什么在這里修改一下還是沒有效果呢?原因就在于如果一個變量用volatile修飾之后,只是會讓其他的線程立即能夠知道當前變量的值是多少,這里就叫做可見性,但是還是解決不了i++這幾個操作的問題,那如何處理,又有人提出用synchronized這個關鍵字,不得不承認,這個關鍵字確實很強大,是能夠解決這個問題,那我們有沒有考慮過這個為什么可以解決這個問題,是如何解決的,那還是簡單的說一下,首先synchronized是屬于JVM級別的,有這個關鍵字的方法或者代碼塊,最后會被解釋成monitorentermonitorexit指令,這兩個字節碼都明確需要一個reference類型的參數來指出要鎖定或者解鎖的對象,像這樣:

public synchronized String f(){
    //code
}

synchronized(object){
    //code
}

看到這里,我們應該能明白synchronized為什么可以解決上面程序的問題,但是我們還應該要明確一個概念就是原子性,換句話說,就是我們在處理一些多線程的問題的時候,應該保證一些共享數據的操作是原子性的,這樣才能保證正確性,看到這里,相信你也有了一個大概的理解,那我們來總結一下,在處理多線程的問題的時候,哪些點是值得注意的,可見性,原子性,有序性,這幾個點是保證多線程能夠正確的一個前提條件,至于什么是有序性,這里涉及到內存指令的重排序,不在討論范圍內,以后再來討論。

這里還要指出一個問題,就是是否我們在處理多線程問題的時候,一定要同步,或者說一定要加鎖,這個也不是一定的,之前網上有一個說笑的方式,就是我們在處理多線程的問題的時候,有時候就會發現,代碼又被寫成了單線程,當然這只是一個玩笑話,但是這里我們也能看出來,是不是單線程的程序就不會有這些問題?答案是肯定的,因為單線程不存在資源競爭的問題,也就不需要再討論了。

那么我們什么時候需要使用同步,什么時候又不需要呢?我們來看一段代碼

    public String f(String s1, String s2, String s3){
        return s1 + s2 +s3;
    }

這是一個字符串拼接的一個方法,我們來反編譯看一下,這里JVM到底是怎么做的?

這里很明顯的能夠看出來,最后是通過StringBuilder來為我們生成了最后的結果,那有人會問,這里線程安全么?是的,這里是線程安全的,因為在這個方法中,雖然也有變量的使用,但是都是屬于線程內部在使用,其他的線程根本不會訪問到或者說這些變量也不會讓其他線程訪問到,我們稱其為沒有方法逃逸,也就是說只能在本線程中使用這些變量,這里是線程安全的,至于什么是逃逸分析,簡單的提一下就是這是JVM的高級優化的一種方式,說的再簡單一點,就是別的線程訪問不到這個變量,這樣的代碼是不需要同步的。

在多線程的問題上面概念比較多,也需要慢慢理解,其實JVM也在多線程的鎖的上面做了很多優化,還有互斥同步非互斥同步,還有很多概念,什么是自旋和自適應自旋鎖消除(順便提一下,上面的字符串拼接的例子就是用到了這種優化方式),鎖粗化,我們下次再繼續分享。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/76658.html

相關文章

  • 淺談Java并發編程系列(二)—— Java內存模型

    摘要:物理計算機并發問題在介紹內存模型之前,先簡單了解下物理計算機中的并發問題?;诟咚倬彺娴拇鎯换ヒ胍粋€新的問題緩存一致性。寫入作用于主內存變量,把操作從工作內存中得到的變量值放入主內存的變量中。 物理計算機并發問題 在介紹Java內存模型之前,先簡單了解下物理計算機中的并發問題。由于處理器的與存儲設置的運算速度有幾個數量級的差距,所以現代計算機加入一層讀寫速度盡可能接近處理器的高速緩...

    Edison 評論0 收藏0
  • 淺談Java并發編程系列(七) —— 深入解析synchronized關鍵字

    摘要:第一個字被稱為。經量級鎖的加鎖過程當一個對象被鎖定時,被復制到當前嘗試獲取鎖的線程的線程棧的鎖記錄空間被復制的官方稱為。根據鎖對象目前是否處于被鎖定狀態,撤銷偏向后恢復到未鎖定或經量級鎖定狀態。 Synchronized關鍵字 synchronized的鎖機制的主要優勢是Java語言內置的鎖機制,因此,JVM可以自由的優化而不影響已存在的代碼。 任何對象都擁有對象頭這一數據結構來支持鎖...

    piglei 評論0 收藏0
  • 淺談Java并發編程系列(四)—— 原子性、可見性與有序性

    摘要:內存模型是圍繞著在并發過程中如何處理原子性可見性和有序性這個特征來建立的,我們來看下哪些操作實現了這個特性??梢娦钥梢娦允侵府斠粋€線程修改了共享變量的值,其他線程能夠立即得知這個修改。 Java內存模型是圍繞著在并發過程中如何處理原子性、可見性和有序性這3個特征來建立的,我們來看下哪些操作實現了這3個特性。 原子性(atomicity): 由Java內存模型來直接保證原子性變量操作包括...

    tianren124 評論0 收藏0
  • 淺談Java中鎖的實現和優化

    摘要:這兩種策略的區別就在于,公平策略會讓等待時間長的線程優先執行,非公平策略則是等待時間長的線程不一定會執行,存在一個搶占資源的問題。 之前有一篇文章我們簡單的談到了Java中同步的問題,但是可能在平常的開發中,有些理論甚至是某些方式是用不到的,但是從程序的角度看,這些理論思想我們可以運用到我們的開發中,比如是不是應該一談到同步問題,就應該想到用synchronized?,什么時候應該用R...

    DevWiki 評論0 收藏0
  • 淺談java中的并發控制

    摘要:并發需要解決的問題功能性問題線程同步面臨兩個問題,想象下有兩個線程在協作工作完成某項任務。鎖可用于規定一個臨界區,同一時間臨界區內僅能由一個線程訪問。并發的數據結構線程安全的容器,如等。 并發指在宏觀上的同一時間內同時執行多個任務。為了滿足這一需求,現代的操作系統都抽象出 線程 的概念,供上層應用使用。 這篇博文不打算詳細展開分析,而是對java并發中的概念和工具做一個梳理。沿著并發模...

    Gilbertat 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<