Java中的synchronized有幾種加鎖方式(實(shí)例詳解)
在Java中,synchronized
關(guān)鍵字提供了內(nèi)置的支持來實(shí)現(xiàn)同步訪問共享資源,以避免并發(fā)問題。synchronized
主要有三種加鎖方式:
1.同步實(shí)例方法
當(dāng)一個(gè)實(shí)例方法被聲明為synchronized
時(shí),該方法將同一時(shí)間只能被一個(gè)線程訪問。鎖是當(dāng)前對(duì)象實(shí)例(即this
)。
public class SynchronizedInstanceMethod { public synchronized void doSomething() { // 同步代碼塊 // 同一時(shí)間只能有一個(gè)線程執(zhí)行這里的代碼 } public static void main(String[] args) { SynchronizedInstanceMethod obj = new SynchronizedInstanceMethod(); // 創(chuàng)建多個(gè)線程訪問obj的doSomething方法,它們將串行執(zhí)行 // ... } }
當(dāng)我們創(chuàng)建了兩個(gè)線程來并發(fā)地增加計(jì)數(shù)器,由于我們使用了synchronized
,因此計(jì)數(shù)器的增加線程是安全的,即使兩個(gè)線程都在嘗試修改同一個(gè)共享變量。在同步實(shí)例方法中,鎖分別是實(shí)例對(duì)象和類對(duì)象。
public class SynchronizedInstanceMethodExample { private int count = 0; // 同步實(shí)例方法,鎖定的是當(dāng)前對(duì)象的實(shí)例(this) public synchronized void increment() { count++; System.out.println(Thread.currentThread().getName() + " incremented count to " + count); } public static void main(String[] args) { final SynchronizedInstanceMethodExample example = new SynchronizedInstanceMethodExample(); // 創(chuàng)建兩個(gè)線程來增加計(jì)數(shù)器 Thread thread1 = new Thread(() -> { for (int i = 0; i < 1000; i++) { example.increment(); } }, "Thread-1"); Thread thread2 = new Thread(() -> { for (int i = 0; i < 1000; i++) { example.increment(); } }, "Thread-2"); // 啟動(dòng)線程 thread1.start(); thread2.start(); // 等待線程完成 try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 輸出最終計(jì)數(shù) System.out.println("Final count: " + example.count); } }
2.同步靜態(tài)方法
當(dāng)一個(gè)靜態(tài)方法被聲明為synchronized
時(shí),該方法將同一時(shí)間只能被一個(gè)線程訪問。鎖是Class對(duì)象,而不是實(shí)例對(duì)象。
public class SynchronizedStaticMethod { public static synchronized void doSomethingStatic() { // 同步代碼塊 // 同一時(shí)間只能有一個(gè)線程執(zhí)行這里的代碼 } public static void main(String[] args) { // 創(chuàng)建多個(gè)線程訪問SynchronizedStaticMethod的doSomethingStatic方法,它們將串行執(zhí)行 // ... } }
當(dāng)我們創(chuàng)建了兩個(gè)線程來并發(fā)地增加計(jì)數(shù)器,由于我們使用了synchronized
,因此計(jì)數(shù)器的增加線程是安全的,即使兩個(gè)線程都在嘗試修改同一個(gè)共享變量。在同步靜態(tài)方法中,鎖分別也是實(shí)例對(duì)象和類對(duì)象。
public class SynchronizedStaticMethodExample { private static int count = 0; // 同步靜態(tài)方法,鎖定的是當(dāng)前對(duì)象的類(Class)對(duì)象 public static synchronized void increment() { count++; System.out.println(Thread.currentThread().getName() + " incremented static count to " + count); } public static void main(String[] args) { // 創(chuàng)建兩個(gè)線程來增加計(jì)數(shù)器 Thread thread1 = new Thread(() -> { for (int i = 0; i < 1000; i++) { increment(); } }, "Thread-1"); Thread thread2 = new Thread(() -> { for (int i = 0; i < 1000; i++) { increment(); } }, "Thread-2"); // 啟動(dòng)線程... // 等待線程完成... // 輸出最終計(jì)數(shù)... // (與上面的例子類似,但省略了重復(fù)的代碼) } }
3.同步代碼塊
我們可以使用synchronized
關(guān)鍵字來定義一個(gè)代碼塊,而不是整個(gè)方法。在這種情況下,你可以指定要獲取的鎖對(duì)象。這提供了更細(xì)粒度的同步控制。
public class SynchronizedBlock { private final Object lock = new Object(); // 用于同步的鎖對(duì)象 public void doSomething() { synchronized (lock) { // 同步代碼塊 // 同一時(shí)間只有一個(gè)線程能夠執(zhí)行這里的代碼 } // 這里的代碼不受同步代碼塊的約束 } public static void main(String[] args) { SynchronizedBlock obj = new SynchronizedBlock(); // 創(chuàng)建多個(gè)線程訪問obj的doSomething方法,但只有在synchronized塊中的代碼將串行執(zhí)行 // ... } }
在上面的SynchronizedBlock
類中,我們創(chuàng)建了一個(gè)私有的Object
實(shí)例lock
作為鎖對(duì)象。當(dāng)線程進(jìn)入synchronized (lock)
塊時(shí),它會(huì)嘗試獲取lock
對(duì)象的鎖。如果鎖已經(jīng)被其他線程持有,那么該線程將被阻塞,直到鎖被釋放。
當(dāng)我們創(chuàng)建了兩個(gè)線程來并發(fā)地增加計(jì)數(shù)器,同步代碼塊的例子中,我們顯式地指定了一個(gè)對(duì)象作為鎖。
public class SynchronizedBlockExample { private final Object lock = new Object(); // 用于同步的鎖對(duì)象 private int count = 0; // 同步代碼塊,指定了鎖對(duì)象 public void increment() { synchronized (lock) { count++; System.out.println(Thread.currentThread().getName() + " incremented count to " + count); } } public static void main(String[] args) { // 類似于上面的例子,但使用SynchronizedBlockExample的increment方法 // ...(省略了重復(fù)的代碼) } }
注意:使用synchronized
時(shí)應(yīng)該盡量避免在持有鎖的情況下執(zhí)行耗時(shí)的操作,因?yàn)檫@會(huì)導(dǎo)致其他等待鎖的線程長時(shí)間阻塞。同時(shí),過度使用synchronized
可能會(huì)導(dǎo)致性能下降,因?yàn)樗鼤?huì)引入線程間的競(jìng)爭(zhēng)和可能的上下文切換。在設(shè)計(jì)并發(fā)程序時(shí),應(yīng)該仔細(xì)考慮同步的粒度,并可能使用其他并發(fā)工具(如ReentrantLock
、Semaphore
、CountDownLatch
等)來提供更細(xì)粒度的控制。
到此這篇關(guān)于java的synchronized有幾種加鎖方式的文章就介紹到這了,更多相關(guān)java synchronized加鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring mvc實(shí)現(xiàn)登錄賬號(hào)單瀏覽器登錄
這篇文章主要為大家詳細(xì)介紹了spring mvc實(shí)現(xiàn)登錄賬號(hào)單瀏覽器登錄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04Maven中的dependencyManagement 實(shí)例詳解
dependencyManagement的中文意思就是依賴關(guān)系管理,它就是為了能通更好統(tǒng)一管理項(xiàng)目的版本號(hào)和各種jar版本號(hào),可以更加方便升級(jí),解決包沖突問題,這篇文章主要介紹了Maven中的dependencyManagement 實(shí)例詳解,需要的朋友可以參考下2024-02-02java Date裝成英文String后,無法再轉(zhuǎn)回Date的解決方案
本文介紹了java Date裝成英文String后,無法再轉(zhuǎn)回Date的解決方案。具有一定的參考價(jià)值,下面跟著小編一起來看下吧2017-01-01mybatis 連接mysql數(shù)據(jù)庫 tinyint 為boolean類型詳解
這篇文章主要介紹了mybatis 連接mysql數(shù)據(jù)庫 tinyint 為boolean類型詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-11-11Java SimpleDateFormat中英文時(shí)間格式化轉(zhuǎn)換詳解
這篇文章主要為大家詳細(xì)介紹了Java SimpleDateFormat中英文時(shí)間格式化轉(zhuǎn)換,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12Java超詳細(xì)教你寫一個(gè)學(xué)籍管理系統(tǒng)案例
這篇文章主要介紹了怎么用Java來寫一個(gè)學(xué)籍管理系統(tǒng),學(xué)籍管理主要涉及到學(xué)生信息的增刪查改,本篇將詳細(xì)的實(shí)現(xiàn),感興趣的朋友跟隨文章往下看看吧2022-03-03