Java 併發及同步相關 Synchronized ReentrantLock

        要了解Java併發,首先需要了解JVM內存模型。JVM內存模型分爲兩個部分,Main Memory和Working Memory. Main Memory爲線程共享,Working Memory爲線程自己所有,存放的是線程所需要的變量的拷貝(線程要對main memory中的內容進行操作的話,首先需要拷貝到自己的workingmemory,一般爲了速度,working memory一般是在cpu的cache中的)。

在這裏Java引入了關鍵字volatile,volatile的變量在被操作的時候不會產生working memory的拷貝,而是直接操作main memory,當然volatile雖然解決了變量的可見性問題,但沒有解決變量操作的原子性的問題,這個還需要synchronized或者CAS相關 操作配合進行。

在多線程中的幾個比較重要的概念:

可見性

也就說假設一個對象中有一個變量i,那麼i是保存在main memory中的,當某一個線程要操作i的時候,首先需要從main memory中將i 加載到這個線程的working memory中,這個時候working memory中就有了一個i的拷貝,這個時候此線程對i的修改都在其working memory中,直到其將i從working memory寫回到mainmemory中,新的i的值才能被其他線程所讀取。從某個意義上說,可見性保證了各個線程的working memory的數據的一致性。
可見性遵循下面一些規則:

  • 當一個線程運行結束的時候,所有寫的變量都會被flush回main memory中。
  • 當一個線程第一次讀取某個變量的時候,會從main memory中讀取最新的。
  • volatile的變量會被立刻寫到main memory中的,在jsr133中,對volatile的語義進行增強,後面會提到
  • 當一個線程釋放鎖後,所有的變量的變化都會flush到main memory中,然後一個使用了這個相同的同步鎖的進程,將會重新加載所有的使用到的變量,這樣就保證了可見性。

原子性

還拿上面的例子來說,原子性就是當某一個線程修改i的值的時候,從取出i到將新的i的值寫給i之間不能有其他線程對i進行任何操作。也就是說保證某個線程對i的操作是原子性的,這樣就可以避免數據髒讀。
通過鎖機制或者CAS(Compare And Set 需要硬件CPU的支持)操作可以保證操作的原子性。



在線程同步上,通常使用到的幾個方法爲Synchronized,ReentrantLock

其性能&區別如下:

synchronized:
在資源競爭不是很激烈的情況下,偶爾會有同步的情形下,synchronized是很合適的。原因在於,編譯程序通常會儘可能的進行優化synchronize,另外可讀性非常好,不管用沒用過5.0多線程包的程序員都能理解。

ReentrantLock:
ReentrantLock提供了多樣化的同步,比如有時間限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在資源競爭不激烈的情形下,性能稍微比synchronized差點點。但是當同步非常激烈的時候,synchronized的性能一下子能下降好幾十倍。而ReentrantLock確還能維持常態。



最後再說說ThreadLocal,ThreadLocal其實維護的是每一個線程的單獨變量,其使用場合一般如下:

1、存放當前session用戶:quake want的jert

  2、存放一些context變量,比如webwork的ActionContext

  3、存放session,比如Spring hibernate orm的session

4.每一條線需要維護自身的變量


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