谈一谈synchronized关键词
1.使用
java中的每一個(gè)對(duì)象都可以作為synchronized的鎖進(jìn)行代碼同步,常見的形式
- 同步代碼塊鎖是synchronized括號(hào)內(nèi)的對(duì)象
- 普通成員方法上,鎖是當(dāng)前的對(duì)象,synchronized(this)
- 靜態(tài)方法上,鎖是當(dāng)前類的Class對(duì)象
2. 原理
synchronized是通過指定某個(gè)對(duì)象進(jìn)行加鎖,那么synchronized的鎖信息肯定是和對(duì)象有關(guān)。Java的對(duì)象頭里的Mark Word字段,默認(rèn)是存儲(chǔ)對(duì)象的HashCode。32位虛擬機(jī)中Mark Word的存儲(chǔ)結(jié)構(gòu)
| 無鎖狀態(tài) | Hash code,偏向鎖0 | 01 |
| 偏向鎖 | 線程ID,偏向鎖1 | 01 |
| 輕量級(jí)鎖 | 指向棧中鎖記錄的指針 | 00 |
| 重量級(jí)鎖 | 指向互斥量的指針 | 10 |
3.鎖升級(jí)
偏向鎖 ==> 輕量級(jí)鎖 ==> 重量級(jí)鎖
鎖只能升級(jí)、不能退化
1.偏向鎖
- 偏向鎖加鎖:Mark Word中記錄了當(dāng)前獲取鎖線程ID,這樣同一個(gè)線程可以多次進(jìn)入同一個(gè)共享代碼塊而無需加鎖。如果是無鎖狀態(tài),則嘗試通過CAS將偏向鎖中的線程id修改為當(dāng)前線程。
- 偏向鎖解鎖:需要等到全局安全點(diǎn)(在這個(gè)時(shí)間點(diǎn)上沒有正在執(zhí)行的字節(jié)碼)會(huì)首先暫停擁有偏向鎖的線程,判斷鎖對(duì)象是否處于被活動(dòng)狀態(tài),撤銷偏向鎖后恢復(fù)到未鎖定或升級(jí)為輕量級(jí)鎖。
2.輕量級(jí)鎖
- 加鎖:在棧幀中創(chuàng)建空間(Displaced Mark Word)存儲(chǔ)Mark Word中內(nèi)容,然后嘗試使用Cas把Mark word中的指針指向棧幀。成功則獲取鎖,失敗則通過自旋獲取鎖,自旋失敗則升級(jí)為重量級(jí)鎖
- 解鎖:通過CAS把棧幀中的(Displaced Mark Word使用CAS替換回Mark Word,成功則說明在期間沒有鎖競(jìng)爭(zhēng),否則喚醒等待線程(已經(jīng)升級(jí)為重量級(jí)鎖)
3.鎖的優(yōu)缺點(diǎn)
| 偏向鎖 | 加鎖和解鎖不需要額外的消耗,和執(zhí)行非同步方法比僅存在納秒級(jí)的差距 | 如果線程間存在鎖競(jìng)爭(zhēng),會(huì)帶來額外的鎖撤銷的消耗 | 適用于只有一個(gè)線程訪問同步塊場(chǎng)景 |
| 輕量級(jí)鎖 | 競(jìng)爭(zhēng)的線程不會(huì)阻塞,提高了程序的響應(yīng)速度 | 如果始終得不到鎖競(jìng)爭(zhēng)的線程使用自旋會(huì)消耗CPU | 追求響應(yīng)時(shí)間,鎖占用時(shí)間很短 |
| 重量級(jí)鎖 | 線程競(jìng)爭(zhēng)不使用自旋,不會(huì)消耗CPU | 線程阻塞,響應(yīng)時(shí)間緩慢 | 追求吞吐量,鎖占用時(shí)間較長(zhǎng) |
4. StringBuilder和StringBuffer
如果你看到別人在非并發(fā)環(huán)境下使用StringBuffer就說,你這里應(yīng)該用StringBuilder啊,用StringBuffer明顯影響性能。這句話前面半句是沒問題的,但是說明顯影響性能這個(gè)就有點(diǎn)顯得不那么專業(yè)了。如果你看明白的了synchronized的鎖升級(jí)就應(yīng)該知道,在單線程環(huán)境下永遠(yuǎn)是偏向鎖,不會(huì)升級(jí)。因此性能開銷可以忽略不計(jì)。
As of release JDK 5, this class has been supplemented with an equivalentclass designed for use by a single thread, link StringBuilder. TheStringBuilder class should generally be used in preference tothis one, as it supports all of the same operations but it is faster, ast performs no synchronization.5. synchronized + String
public class TTT {public static void main(String[] args) throws ParseException, InterruptedException {new MyThread("A").start();synchronized (new String("B")) {new MyThread("B").start();}new MyThread("A").start();}public static void synchronizeMethod(String str) throws InterruptedException {synchronized (str) {TimeUnit.SECONDS.sleep(2);System.out.println(str);}}static class MyThread extends Thread {String str;public MyThread(String str) {this.str = str;}@Overridepublic void run() {try {synchronizeMethod(str);} catch (InterruptedException e) {e.printStackTrace();}}} }你知道上面代碼的執(zhí)行情況嗎。如果不明白那說明synchronized使用和String的內(nèi)存分配情況還有欠缺。
轉(zhuǎn)載于:https://www.cnblogs.com/lizo/p/7570740.html
總結(jié)
以上是生活随笔為你收集整理的谈一谈synchronized关键词的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCL快速入门
- 下一篇: 高通AR系列与MTK芯片对比专业详解