官术网_书友最值得收藏!

2.2 Java中的synchronized同步鎖

導(dǎo)致線程安全問題的根本原因在于,存在多個線程同時操作一個共享資源,要想解決這個問題,就需要保證對共享資源訪問的獨占性,因此人們在Java中提供了synchronized關(guān)鍵字,我們稱之為同步鎖,它可以保證在同一時刻,只允許一個線程執(zhí)行某個方法或代碼塊。

synchronized同步鎖具有互斥性,這相當(dāng)于線程由并行執(zhí)行變成串行執(zhí)行,保證了線程的安全性,但是損失了性能。下面我們先來看一下synchronized的使用方法。

2.2.1 synchronized的使用方法

synchronized的使用方法比較簡單,修飾方式有如下兩種。

? 作用在方法級別,表示針對m1()方法加鎖,當(dāng)多個線程同時訪問m1()方法時,同一時刻只有一個線程能執(zhí)行。

? 作用在代碼塊級別,表示針對某一段線程不安全的代碼加鎖,只有訪問到synchronized(this)這行代碼時,才會去競爭鎖資源。

了解了synchronized的基本使用語法之后,我們來看如圖2-4所示的流程,它針對2.1節(jié)的案例增加了synchronized同步鎖之后的執(zhí)行流程。簡單地說,當(dāng)多個線程同時訪問加synchronized關(guān)鍵字修飾的方法時,需要先搶占一個鎖標(biāo)記,只有搶到鎖標(biāo)記的線程才有資格調(diào)用incr()方法。這就使得在同一時刻只有一個線程執(zhí)行i++操作,從而解決了原子性問題。

圖2-4 增加了synchronized同步鎖之后的執(zhí)行流程

2.2.2 了解synchronized同步鎖的作用范圍

我們對一個方法增加synchronized關(guān)鍵字后,當(dāng)多個線程訪問該方法時,整個執(zhí)行過程會變成串行執(zhí)行,這種執(zhí)行方式很明顯會影響程序的性能,那么如何做好安全性及性能的平衡呢?

實際上,synchronized關(guān)鍵字只需要保護(hù)可能存在線程安全問題的代碼,因此,我們可以通過控制同步鎖的作用范圍來實現(xiàn)這個平衡機(jī)制。在synchronized中,提供了兩種鎖,一是類鎖,二是對象鎖。

類鎖

類鎖是全局鎖,當(dāng)多個線程調(diào)用不同對象實例的同步方法時會產(chǎn)生互斥,具體實現(xiàn)方式如下。

? 修飾靜態(tài)方法:

? 修飾代碼塊,synchronized中的鎖對象是類,也就是Lock.class。

下面這段程序使用類鎖來實現(xiàn)跨對象實例,從而實現(xiàn)互斥的功能。

? 該程序中定義了一個m1()方法,該方法中實現(xiàn)了一個循環(huán)打印當(dāng)前線程名稱的邏輯,并且這段邏輯是用類鎖來保護(hù)的。

? 在main()方法中定義了兩個SynchronizedExample對象實例se1和se2,又分別定義了兩個線程來調(diào)用這兩個實例的m1()方法。

根據(jù)類鎖的作用范圍可以知道,即便是多個對象實例,也能夠達(dá)到互斥的目的,因此最終輸出的結(jié)果是:哪個線程搶到了鎖,哪個線程就持續(xù)打印自己的線程名稱。

對象鎖

對象鎖是實例鎖,當(dāng)多個線程調(diào)用同一個對象實例的同步方法時會產(chǎn)生互斥,具體實現(xiàn)方式如下。

? 修飾普通方法:

? 修飾代碼塊,synchronized中的鎖對象是普通對象實例。

下面這段程序演示了對象鎖的使用方法,代碼如下。

我們先來看一下打印結(jié)果。

從以上結(jié)果中我們發(fā)現(xiàn),對于幾乎相同的代碼,在使用對象鎖的情況下,當(dāng)兩個線程分別訪問兩個不同對象實例的m1()方法時,并沒有達(dá)到兩者互斥的目的,看起來似乎鎖沒有生效,實際上并不是鎖沒有生效,問題的根源在于synchronized(lock)中鎖對象lock的作用范圍過小。

Class是在JVM啟動過程中加載的,每個.class文件被裝載后會產(chǎn)生一個Class對象,Class對象在JVM進(jìn)程中是全局唯一的。通過static修飾的成員對象及方法的生命周期都屬于類級別,它們會隨著類的定義被分配和裝載到內(nèi)存,隨著類被卸載而回收。

實例對象的生命周期伴隨著實例對象的創(chuàng)建而開始,同時伴隨著實例對象的回收而結(jié)束。

因此,類鎖和對象鎖最大的區(qū)別是鎖對象lock的生命周期不同,如果要達(dá)到多個線程互斥,那么多個線程必須要競爭同一個對象鎖。

在上述代碼中,通過Object lock=new Object();構(gòu)建的鎖對象的生命周期是由Synchronized-ForObjectExample對象的實例來決定的,不同的SynchronizedForObjectExample實例會有不同的lock鎖對象,由于沒有形成競爭,所以不會實現(xiàn)互斥的效果。如果想要讓上述程序達(dá)到同步的目的,那么我們可以對lock鎖對象增加static關(guān)鍵字。

主站蜘蛛池模板: 贵阳市| 黄大仙区| 安泽县| 崇州市| 宜州市| 吉林市| 黔东| 东山县| 泰宁县| 合水县| 巫山县| 西和县| 尖扎县| 科技| 吉首市| 阿瓦提县| 洛川县| 洛南县| 凉城县| 绥棱县| 盘山县| 奉贤区| 嵊泗县| 永修县| 缙云县| 谢通门县| 韶关市| 格尔木市| 平凉市| 余姚市| 营山县| 仁布县| 涞源县| 朝阳市| 阳原县| 玉树县| 蒙阴县| 马公市| 东兰县| 肥乡县| 岳阳市|