Java:这是一份全面 详细的 Synchronized关键字 学习指南
前言
- 在Java中,有一個常被忽略 但 非常重要的關(guān)鍵字Synchronized
- 今天,我將詳細(xì)講解 Java關(guān)鍵字Synchronized的所有知識,希望你們會喜歡
目錄
1. 定義
Java中的1個關(guān)鍵字
2. 作用
保證同一時刻最多只有1個線程執(zhí)行 被Synchronized修飾的方法 / 代碼
其他線程 必須等待當(dāng)前線程執(zhí)行完該方法 / 代碼塊后才能執(zhí)行該方法 / 代碼塊
3. 應(yīng)用場景
保證線程安全,解決多線程中的并發(fā)同步問題(實現(xiàn)的是阻塞型并發(fā)),具體場景如下:
4. 原理
監(jiān)視器鎖(monitor)的本質(zhì) 依賴于 底層操作系統(tǒng)的互斥鎖(Mutex Lock)實現(xiàn)
5. 具體使用
Synchronized 用于 修飾 代碼塊、類的實例方法 & 靜態(tài)方法
5.1 使用規(guī)則
5.2 鎖的類型 & 等級
- 由于Synchronized 會修飾 代碼塊、類的實例方法 & 靜態(tài)方法,故分為不同鎖的類型
- 具體如下
- 之間的區(qū)別
5.3 使用方式
/*** 對象鎖*/public class Test{ // 對象鎖:形式1(方法鎖) public synchronized void Method1(){ System.out.println("我是對象鎖也是方法鎖"); try{ Thread.sleep(500); } catch (InterruptedException e){ e.printStackTrace(); } } // 對象鎖:形式2(代碼塊形式) public void Method2(){ synchronized (this){ System.out.println("我是對象鎖"); try{ Thread.sleep(500); } catch (InterruptedException e){ e.printStackTrace(); } } } }/*** 方法鎖(即對象鎖中的形式1)*/public synchronized void Method1(){ System.out.println("我是對象鎖也是方法鎖"); try{ Thread.sleep(500); } catch (InterruptedException e){ e.printStackTrace(); } } /*** 類鎖*/ public class Test{ // 類鎖:形式1 :鎖靜態(tài)方法public static synchronized void Method1(){ System.out.println("我是類鎖一號"); try{ Thread.sleep(500); } catch (InterruptedException e){ e.printStackTrace(); } } // 類鎖:形式2 :鎖靜態(tài)代碼塊public void Method2(){ synchronized (Test.class){ System.out.println("我是類鎖二號"); try{ Thread.sleep(500); } catch (InterruptedException e){ e.printStackTrace(); } } } }- 9
5.4 特別注意
Synchronized修飾方法時存在缺陷:若修飾1個大的方法,將會大大影響效率
-
示例
若使用Synchronized關(guān)鍵字修飾 線程類的run(),由于run()在線程的整個生命期內(nèi)一直在運(yùn)行,因此將導(dǎo)致它對本類任何Synchronized方法的調(diào)用都永遠(yuǎn)不會成功 -
解決方案
使用 Synchronized關(guān)鍵字聲明代碼塊
該解決方案靈活性高:可針對任意代碼塊 & 任意指定上鎖的對象
代碼如下synchronized(syncObject) { // 訪問或修改被鎖保護(hù)的共享狀態(tài) // 上述方法 必須 獲得對象 syncObject(類實例或類)的鎖 }6. 特點(diǎn)
注:原子性、可見性、有序性的定義
7. 其他控制并發(fā) / 線程同步方式
7.1 Lock、ReentrantLock
- 簡介
- 區(qū)別
7.2 CAS
7.2.1 定義
Compare And Swap,即 比較 并 交換,是一種解決并發(fā)操作的樂觀鎖
synchronized鎖住的代碼塊:同一時刻只能由一個線程訪問,屬于悲觀鎖
7.2.2 原理
// CAS的操作參數(shù) 內(nèi)存位置(A) 預(yù)期原值(B) 預(yù)期新值(C)// 使用CAS解決并發(fā)的原理: // 1. 首先比較A、B,若相等,則更新A中的值為C、返回True;若不相等,則返回false; // 2. 通過死循環(huán),以不斷嘗試嘗試更新的方式實現(xiàn)并發(fā)// 偽代碼如下 public boolean compareAndSwap(long memoryA, int oldB, int newC){if(memoryA.get() == oldB){memoryA.set(newC);return true;}return false; }7.2.3 優(yōu)點(diǎn)
資源耗費(fèi)少:相對于synchronized,省去了掛起線程、恢復(fù)線程的開銷
但,若遲遲得不到更新,死循環(huán)對CPU資源也是一種浪費(fèi)
7.2.4 具體實現(xiàn)方式
- 使用CAS有個“先檢查后執(zhí)行”的操作
- 而這種操作在Java中是典型的不安全的操作,所以 CAS在實際中是由C++通過調(diào)用CPU指令實現(xiàn)的
- 具體過程
7.2.5 典型應(yīng)用:AtomicInteger
對 i++ 與 i–,通過compareAndSet & 一個死循環(huán)實現(xiàn)
而compareAndSet函數(shù)內(nèi)部 = 通過jni操作CAS指令。直到CAS操作成功跳出循環(huán)
private volatile int value; /** * Gets the current value. * * @return the current value */ public final int get() { return value; } /** * Atomically increments by one the current value. * * @return the previous value */ public final int getAndIncrement() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return current; } } /** * Atomically decrements by one the current value. * * @return the previous value */ public final int getAndDecrement() { for (;;) { int current = get(); int next = current - 1; if (compareAndSet(current, next)) return current; } }8. 總結(jié)
-
本文主要對Java中常被忽略 但 非常重要的關(guān)鍵字Synchronized進(jìn)行講解
總結(jié)
以上是生活随笔為你收集整理的Java:这是一份全面 详细的 Synchronized关键字 学习指南的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python中带*(单星号)的变量和**
- 下一篇: shiro学习(14):springMV