淺談synchronized加鎖this和class的區(qū)別
synchronized 是 Java 語(yǔ)言中處理并發(fā)問(wèn)題的一種常用手段,它也被我們親切的稱之為“Java 內(nèi)置鎖”,由此可見(jiàn)其地位之高。然而 synchronized 卻有著多種用法,當(dāng)它修飾不同對(duì)象時(shí),其意義也是不同的,下面我們一起來(lái)看。
synchronized 用法
synchronized 可以用來(lái)修飾普通方法、靜態(tài)方法和代碼塊。
① 修飾普通方法
/**
* synchronized 修飾普通方法
*/
public synchronized void method() {
// .......
}
當(dāng) synchronized 修飾普通方法時(shí),被修飾的方法被稱為同步方法,其作用范圍是整個(gè)方法,作用的對(duì)象是調(diào)用這個(gè)方法的對(duì)象。
② 修飾靜態(tài)方法
/**
* synchronized 修飾靜態(tài)方法
*/
public static synchronized void staticMethod() {
// .......
}
當(dāng) synchronized 修飾靜態(tài)的方法時(shí),其作用的范圍是整個(gè)方法,作用對(duì)象是調(diào)用這個(gè)類的所有對(duì)象。
③ 修飾代碼塊
為了減少鎖的粒度,我們可以選擇在一個(gè)方法中的某個(gè)部分使用 synchronized 來(lái)修飾(一段代碼塊),從而實(shí)現(xiàn)對(duì)一個(gè)方法中的部分代碼進(jìn)行加鎖,實(shí)現(xiàn)代碼如下:
public void classMethod() throws InterruptedException {
// 前置代碼...
// 加鎖代碼
synchronized (SynchronizedExample.class) {
// ......
}
// 后置代碼...
}
以上代碼在執(zhí)行時(shí),被修飾的代碼塊稱為同步語(yǔ)句塊,其作用范圍是大括號(hào)“{}”括起來(lái)的代碼塊,作用的對(duì)象是調(diào)用這個(gè)代碼塊的對(duì)象。
但以上代碼,除了可以加鎖 class 之外,還可以加鎖 this,具體示例如下:
public void classMethod() throws InterruptedException {
// 前置處理代碼...
synchronized (this) {
// ......
}
// 后置處理代碼...
}
那問(wèn)題來(lái)了,使用 synchronized 加鎖 this 和 class 的區(qū)別是什么?不都是加鎖同一個(gè)類嗎?
答案還真不是,加鎖 this 和 class 區(qū)別還是很大的。下面我們通過(guò)以下 4 個(gè)示例,來(lái)看二者之間的區(qū)別。
1.加鎖 class 共享一個(gè)類實(shí)例
首先,我們創(chuàng)建 5 個(gè)線程,調(diào)用同一個(gè)對(duì)象下 synchronized 加鎖的 class 代碼,具體示例如下:
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class SynchronizedExample {
public static void main(String[] args) {
// 創(chuàng)建當(dāng)前類實(shí)例
final SynchronizedExample example = new SynchronizedExample();
// 創(chuàng)建 5 個(gè)線程執(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("當(dāng)前執(zhí)行線程:%s,執(zhí)行時(shí)間:%s",
Thread.currentThread().getName(), new Date()));
TimeUnit.SECONDS.sleep(1);
}
}
}
以上程序的執(zhí)行結(jié)果如下:

從上述結(jié)果可以看出,這 5 個(gè)線程共享的是同一把鎖。
2.加鎖 class 創(chuàng)建多個(gè)實(shí)例
接下來(lái),我們創(chuàng)建 5 個(gè)線程,調(diào)用不同對(duì)象下 synchronized 加鎖的 class 代碼,具體示例如下:
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class SynchronizedExample {
public static void main(String[] args) {
// 創(chuàng)建 5 個(gè)線程執(zhí)行任務(wù)
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 創(chuàng)建類實(shí)例
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("當(dāng)前執(zhí)行線程:%s,執(zhí)行時(shí)間:%s",
Thread.currentThread().getName(), new Date()));
TimeUnit.SECONDS.sleep(1);
}
}
}
以上程序的執(zhí)行結(jié)果如下:

從上述結(jié)果可以看出,雖然是不同的對(duì)象,但它們使用的仍然是同一把鎖。
3.加鎖 this 共享一個(gè)類實(shí)例
接下來(lái),我們創(chuàng)建 5 個(gè)線程,調(diào)用 synchronized 加鎖 this 的示例。首先我們這 5 個(gè)線程調(diào)用同一個(gè)對(duì)象的加鎖方法,示例代碼如下:
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class SynchronizedExample {
public static void main(String[] args) {
// 創(chuàng)建當(dāng)前類實(shí)例
final SynchronizedExample example = new SynchronizedExample();
// 創(chuàng)建 5 個(gè)線程執(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("當(dāng)前執(zhí)行線程:%s,執(zhí)行時(shí)間:%s",
Thread.currentThread().getName(), new Date()));
TimeUnit.SECONDS.sleep(1);
}
}
}
以上程序的執(zhí)行結(jié)果如下:

從上述結(jié)果可以看出,以上線程使用的都是同一把鎖。
4.加鎖 this 創(chuàng)建多個(gè)類實(shí)例
最后一個(gè)示例最為特殊,我們使用 synchronized 加鎖 this,讓這 5 個(gè)線程調(diào)用各自創(chuàng)建對(duì)象的方法,具體示例如下:
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class SynchronizedExample {
public static void main(String[] args) {
// 創(chuàng)建 5 個(gè)線程執(zhí)行任務(wù)
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 創(chuàng)建(多個(gè))類實(shí)例
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("當(dāng)前執(zhí)行線程:%s,執(zhí)行時(shí)間:%s",
Thread.currentThread().getName(), new Date()));
TimeUnit.SECONDS.sleep(1);
}
}
}
以上程序的執(zhí)行結(jié)果如下:

從上述結(jié)果可以看出,當(dāng)使用 synchronized 加鎖 this 時(shí),如果線程調(diào)用的不是同一個(gè)對(duì)象,那么這些線程之間使用的鎖都是自己獨(dú)立的鎖,這個(gè)結(jié)果就和 synchronized 加鎖 class 的結(jié)果完全不同了。
總結(jié)
通過(guò)以上 4 個(gè)示例我們可以得出結(jié)論,當(dāng)使用 synchronized 加鎖 class 時(shí),無(wú)論共享一個(gè)對(duì)象還是創(chuàng)建多個(gè)對(duì)象,它們用的都是同一把鎖,而使用 synchronized 加鎖 this 時(shí),只有同一個(gè)對(duì)象會(huì)使用同一把鎖,不同對(duì)象之間的鎖是不同的。
到此這篇關(guān)于淺談synchronized加鎖this和class的區(qū)別的文章就介紹到這了,更多相關(guān)synchronized this class內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用SpringBoot編寫(xiě)一個(gè)優(yōu)雅的單元測(cè)試
這篇文章主要為大家詳細(xì)介紹了如何使用SpringBoot編寫(xiě)一個(gè)優(yōu)雅的單元測(cè)試,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-07-07
spring boot使用i18n時(shí)properties文件中文亂碼問(wèn)題的解決方法
這篇文章主要介紹了spring boot使用i18n時(shí)properties文件中文亂碼問(wèn)題的解決方法,需要的朋友可以參考下2017-11-11
Java反射之靜態(tài)加載和動(dòng)態(tài)加載的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇Java反射之靜態(tài)加載和動(dòng)態(tài)加載的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10
JFINAL+Ajax傳參 array 數(shù)組方法 獲取request中數(shù)組操作
這篇文章主要介紹了JFINAL+Ajax傳參 array 數(shù)組方法 獲取request中數(shù)組操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08
Spring Cloud 整合Apache-SkyWalking實(shí)現(xiàn)鏈路跟蹤的方法
這篇文章主要介紹了Spring Cloud 整合Apache-SkyWalking鏈路跟蹤的示例代碼,代碼簡(jiǎn)單易懂,通過(guò)圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06

