淺談synchronized加鎖this和class的區(qū)別
synchronized 是 Java 語言中處理并發(fā)問題的一種常用手段,它也被我們親切的稱之為“Java 內(nèi)置鎖”,由此可見其地位之高。然而 synchronized 卻有著多種用法,當它修飾不同對象時,其意義也是不同的,下面我們一起來看。
synchronized 用法
synchronized 可以用來修飾普通方法、靜態(tài)方法和代碼塊。
① 修飾普通方法
/** * synchronized 修飾普通方法 */ public synchronized void method() { // ....... }
當 synchronized 修飾普通方法時,被修飾的方法被稱為同步方法,其作用范圍是整個方法,作用的對象是調(diào)用這個方法的對象。
② 修飾靜態(tài)方法
/** * synchronized 修飾靜態(tài)方法 */ public static synchronized void staticMethod() { // ....... }
當 synchronized 修飾靜態(tài)的方法時,其作用的范圍是整個方法,作用對象是調(diào)用這個類的所有對象。
③ 修飾代碼塊
為了減少鎖的粒度,我們可以選擇在一個方法中的某個部分使用 synchronized 來修飾(一段代碼塊),從而實現(xiàn)對一個方法中的部分代碼進行加鎖,實現(xiàn)代碼如下:
public void classMethod() throws InterruptedException { // 前置代碼... // 加鎖代碼 synchronized (SynchronizedExample.class) { // ...... } // 后置代碼... }
以上代碼在執(zhí)行時,被修飾的代碼塊稱為同步語句塊,其作用范圍是大括號“{}”括起來的代碼塊,作用的對象是調(diào)用這個代碼塊的對象。
但以上代碼,除了可以加鎖 class 之外,還可以加鎖 this,具體示例如下:
public void classMethod() throws InterruptedException { // 前置處理代碼... synchronized (this) { // ...... } // 后置處理代碼... }
那問題來了,使用 synchronized 加鎖 this 和 class 的區(qū)別是什么?不都是加鎖同一個類嗎?
答案還真不是,加鎖 this 和 class 區(qū)別還是很大的。下面我們通過以下 4 個示例,來看二者之間的區(qū)別。
1.加鎖 class 共享一個類實例
首先,我們創(chuàng)建 5 個線程,調(diào)用同一個對象下 synchronized 加鎖的 class 代碼,具體示例如下:
import java.util.Date; import java.util.concurrent.TimeUnit; public class SynchronizedExample { public static void main(String[] args) { // 創(chuàng)建當前類實例 final SynchronizedExample example = new SynchronizedExample(); // 創(chuàng)建 5 個線程執(zhí)行任務(wù) for (int i = 0; i < 5; i++) { new Thread(new Runnable() { @Override public void run() { try { // 調(diào)用 synchronized 修飾的 class 方法 example.classMethod(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } /** * synchronized 修飾的 class 方法 * @throws InterruptedException */ public void classMethod() throws InterruptedException { synchronized (SynchronizedExample.class) { System.out.println(String.format("當前執(zhí)行線程:%s,執(zhí)行時間:%s", Thread.currentThread().getName(), new Date())); TimeUnit.SECONDS.sleep(1); } } }
以上程序的執(zhí)行結(jié)果如下:
從上述結(jié)果可以看出,這 5 個線程共享的是同一把鎖。
2.加鎖 class 創(chuàng)建多個實例
接下來,我們創(chuàng)建 5 個線程,調(diào)用不同對象下 synchronized 加鎖的 class 代碼,具體示例如下:
import java.util.Date; import java.util.concurrent.TimeUnit; public class SynchronizedExample { public static void main(String[] args) { // 創(chuàng)建 5 個線程執(zhí)行任務(wù) for (int i = 0; i < 5; i++) { new Thread(new Runnable() { @Override public void run() { try { // 創(chuàng)建類實例 SynchronizedExample example = new SynchronizedExample(); // 調(diào)用 synchronized 修飾的 class 方法 example.classMethod(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } /** * synchronized 修飾的 class 方法 * @throws InterruptedException */ public void classMethod() throws InterruptedException { synchronized (SynchronizedExample.class) { System.out.println(String.format("當前執(zhí)行線程:%s,執(zhí)行時間:%s", Thread.currentThread().getName(), new Date())); TimeUnit.SECONDS.sleep(1); } } }
以上程序的執(zhí)行結(jié)果如下:
從上述結(jié)果可以看出,雖然是不同的對象,但它們使用的仍然是同一把鎖。
3.加鎖 this 共享一個類實例
接下來,我們創(chuàng)建 5 個線程,調(diào)用 synchronized 加鎖 this 的示例。首先我們這 5 個線程調(diào)用同一個對象的加鎖方法,示例代碼如下:
import java.util.Date; import java.util.concurrent.TimeUnit; public class SynchronizedExample { public static void main(String[] args) { // 創(chuàng)建當前類實例 final SynchronizedExample example = new SynchronizedExample(); // 創(chuàng)建 5 個線程執(zhí)行任務(wù) for (int i = 0; i < 5; i++) { new Thread(new Runnable() { @Override public void run() { try { // 調(diào)用 synchronized 修飾的 this 方法 example.thisMethod(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } /** * synchronized 修飾的 this 方法 * @throws InterruptedException */ public void thisMethod() throws InterruptedException { synchronized (this) { System.out.println(String.format("當前執(zhí)行線程:%s,執(zhí)行時間:%s", Thread.currentThread().getName(), new Date())); TimeUnit.SECONDS.sleep(1); } } }
以上程序的執(zhí)行結(jié)果如下:
從上述結(jié)果可以看出,以上線程使用的都是同一把鎖。
4.加鎖 this 創(chuàng)建多個類實例
最后一個示例最為特殊,我們使用 synchronized 加鎖 this,讓這 5 個線程調(diào)用各自創(chuàng)建對象的方法,具體示例如下:
import java.util.Date; import java.util.concurrent.TimeUnit; public class SynchronizedExample { public static void main(String[] args) { // 創(chuàng)建 5 個線程執(zhí)行任務(wù) for (int i = 0; i < 5; i++) { new Thread(new Runnable() { @Override public void run() { try { // 創(chuàng)建(多個)類實例 SynchronizedExample example = new SynchronizedExample(); // 調(diào)用 synchronized 修飾的 this 方法 example.thisMethod(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } /** * synchronized 修飾的 this 方法 * @throws InterruptedException */ public void thisMethod() throws InterruptedException { synchronized (this) { System.out.println(String.format("當前執(zhí)行線程:%s,執(zhí)行時間:%s", Thread.currentThread().getName(), new Date())); TimeUnit.SECONDS.sleep(1); } } }
以上程序的執(zhí)行結(jié)果如下:
從上述結(jié)果可以看出,當使用 synchronized 加鎖 this 時,如果線程調(diào)用的不是同一個對象,那么這些線程之間使用的鎖都是自己獨立的鎖,這個結(jié)果就和 synchronized 加鎖 class 的結(jié)果完全不同了。
總結(jié)
通過以上 4 個示例我們可以得出結(jié)論,當使用 synchronized 加鎖 class 時,無論共享一個對象還是創(chuàng)建多個對象,它們用的都是同一把鎖,而使用 synchronized 加鎖 this 時,只有同一個對象會使用同一把鎖,不同對象之間的鎖是不同的。
到此這篇關(guān)于淺談synchronized加鎖this和class的區(qū)別的文章就介紹到這了,更多相關(guān)synchronized this class內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java下3中XML解析 DOM方式、SAX方式和StAX方式
目前我知道的JAVA解析XML的方式有:DOM, SAX, StAX;如果選用這幾種,感覺還是有點麻煩;如果使用:JAXB(Java Architecture for XML Binding),個人覺得太方便了2013-04-04淺談Java成員變量與屬性的區(qū)別(簡單最易懂的解釋)
下面小編就為大家?guī)硪黄獪\談Java成員變量與屬性的區(qū)別(簡單最易懂的解釋)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-05-05springboot整合mail實現(xiàn)郵箱的發(fā)送功能
本文分步驟給大家介紹springboot整合mail實現(xiàn)郵箱的發(fā)送功能,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-09-09