日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

詳解Java并發編程之內置鎖(synchronized)

瀏覽:23日期:2022-08-15 16:17:13
簡介

synchronized在JDK5.0的早期版本中是重量級鎖,效率很低,但從JDK6.0開始,JDK在關鍵字synchronized上做了大量的優化,如偏向鎖、輕量級鎖等,使它的效率有了很大的提升。

synchronized的作用是實現線程間的同步,當多個線程都需要訪問共享代碼區域時,對共享代碼區域進行加鎖,使得每一次只能有一個線程訪問共享代碼區域,從而保證線程間的安全性。

因為沒有顯式的加鎖和解鎖過程,所以稱之為隱式鎖,也叫作內置鎖、監視器鎖。

如下實例,在沒有使用synchronized的情況下,多個線程訪問共享代碼區域時,可能會出現與預想中不同的結果。

public class Apple implements Runnable { private int appleCount = 5; @Override public void run() { eatApple(); } public void eatApple(){ appleCount--; System.out.println(Thread.currentThread().getName() + '吃了一個蘋果,還剩' + appleCount + '個蘋果'); } public static void main(String[] args) { Apple apple = new Apple(); Thread t1 = new Thread(apple, '小強'); Thread t2 = new Thread(apple, '小明'); Thread t3 = new Thread(apple, '小花'); Thread t4 = new Thread(apple, '小紅'); Thread t5 = new Thread(apple, '小黑'); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); }}

可能會輸出如下結果:

小強吃了一個蘋果,還剩3個蘋果小黑吃了一個蘋果,還剩3個蘋果小明吃了一個蘋果,還剩2個蘋果小花吃了一個蘋果,還剩1個蘋果小紅吃了一個蘋果,還剩0個蘋果

輸出結果異常的原因是eatApple方法里操作不是原子的,如當A線程完成appleCount的賦值,還沒有輸出,B線程獲取到appleCount的最新值,并完成賦值操作,然后A和B同時輸出。(A,B線程分別對應小黑、小強)

如果改下eatApple方法如下,還會不會有線程安全問題呢?

public void eatApple(){System.out.println(Thread.currentThread().getName() + '吃了一個蘋果,還剩' + --appleCount + '個蘋果');}

還是會有的,因為--appleCount不是原子操作,--appleCount可以用另外一種寫法表示:appleCount = appleCount - 1,還是有可能會出現以上的異常輸出結果。

synchronized的使用

synchronized分為同步方法和同步代碼塊兩種用法,當每個線程訪問同步方法或同步代碼塊區域時,首先需要獲得對象的鎖,搶到鎖的線程可以繼續執行,搶不到鎖的線程則阻塞,等待搶到鎖的線程執行完成后釋放鎖。

1.同步代碼塊

鎖的對象是object:

public class Apple implements Runnable { private int appleCount = 5; private Object object = new Object(); @Override public void run() { eatApple(); } public void eatApple(){//同步代碼塊,此時鎖的對象是object synchronized (object) { appleCount--; System.out.println(Thread.currentThread().getName() + '吃了一個蘋果,還剩' + appleCount + '個蘋果'); } } //...省略main方法}

2.同步方法,修飾普通方法

鎖的對象是當前類的實例對象:

public class Apple implements Runnable { private int appleCount = 5; @Override public void run() { eatApple(); } public synchronized void eatApple() { appleCount--; System.out.println(Thread.currentThread().getName() + '吃了一個蘋果,還剩' + appleCount + '個蘋果'); } //...省略main方法}

等價于以下同步代碼塊的寫法:

public void eatApple() {synchronized (this) {appleCount--;System.out.println(Thread.currentThread().getName() + '吃了一個蘋果,還剩' + appleCount + '個蘋果');}}

3.同步方法,修飾靜態方法

鎖的對象是當前類的class對象:

public class Apple implements Runnable { private static int appleCount = 5; @Override public void run() { eatApple(); } public synchronized static void eatApple() { appleCount--; System.out.println(Thread.currentThread().getName() + '吃了一個蘋果,還剩' + appleCount + '個蘋果'); } //...省略main方法}

等價于以下同步代碼塊的寫法:

public static void eatApple() {synchronized (Apple.class) {appleCount--;System.out.println(Thread.currentThread().getName() + '吃了一個蘋果,還剩' + appleCount + '個蘋果');}}

4.同步方法和同步代碼塊的區別

a.同步方法鎖的對象是當前類的實例對象或者當前類的class對象,而同步代碼塊鎖的對象可以是任意對象。

b.同步方法是使用synchronized修飾方法,而同步代碼塊是使用synchronized修飾共享代碼區域。同步代碼塊相對于同步方法來說粒度更細,鎖的區域更小,一般鎖范圍越小效率就越高。如下情況顯然同步代碼塊更適用:

public static void eatApple() {//不需要同步的耗時操作1//...synchronized (Apple.class) {appleCount--;System.out.println(Thread.currentThread().getName() + '吃了一個蘋果,還剩' + appleCount + '個蘋果');}//不需要同步的耗時操作2//...}

內置鎖的可重入性

內置鎖的可重入性是指當某個線程試圖獲取一個它已經持有的鎖時,它總是可以獲取成功。如下:

public static void eatApple() {synchronized (Apple.class) {synchronized (Apple.class) {synchronized (Apple.class) {appleCount--;System.out.println(Thread.currentThread().getName() + '吃了一個蘋果,還剩' + appleCount + '個蘋果');}}}}

如果鎖不是可重入的,那么假如某線程持有了該鎖,然后又需要等待持有該鎖的線程釋放鎖,這不就造成死鎖了嗎?

synchronized可以被繼承嗎?

synchronized不可以被繼承,如果子類中重寫后的方法需要實現同步,則需要手動添加synchronized關鍵字。

public class AppleParent { public synchronized void eatApple(){ }}public class Apple extends AppleParent implements Runnable { private int appleCount = 5; @Override public void run() { eatApple(); } @Override public void eatApple() { appleCount--; System.out.println(Thread.currentThread().getName() + '吃了一個蘋果,還剩' + appleCount + '個蘋果'); } //...省略main方法}基于內置鎖的等待和喚醒

基于內置鎖的等待和喚醒是使用Object類中的wait()和notify()或notifyAll()來實現的。這些方法的調用前提是已經持有對應的鎖,所以只能在同步方法或者同步代碼塊里調用。如果在沒有獲取到對應鎖的情況下調用則會拋出IllegalMonitorStateException異常。下面介紹下相關的幾個方法:

wait():使當前線程無限期地等待,直到另一個線程調用notify()或notifyAll()。

wait(long timeout):指定一個超時時間,超時時間過后線程將會被自動喚醒。線程也可以在超時時間之前被notify()或notifyAll()喚醒。注意,wait(0)等同于調用wait()。

wait(long timeout, int nanos):類似于wait(long timeout),主要區別是wait(long timeout, int nanos)提供了更高的精度。

notify():隨機喚醒一個在相同鎖對象上等待的線程。

notifyAll():喚醒所有在相同鎖對象上等待的線程。

一個簡單的等待喚醒實例:

public class Apple { //蘋果數量 private int appleCount = 0; /** * 買蘋果 */ public synchronized void getApple() { try { while (appleCount != 0) { wait(); } } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println(Thread.currentThread().getName() + '買了5個蘋果'); appleCount = 5; notify(); } /** * 吃蘋果 */ public synchronized void eatApple() { try { while (appleCount == 0) { wait(); } } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println(Thread.currentThread().getName() + '吃了1個蘋果'); appleCount--; notify(); }}

/** * 生產者,買蘋果 */public class Producer extends Thread{ private Apple apple; public Producer(Apple apple, String name){ super(name); this.apple = apple; } @Override public void run(){ while (true) apple.getApple(); }}/** * 消費者,吃蘋果 */public class Consumer extends Thread{ private Apple apple; public Consumer(Apple apple, String name){ super(name); this.apple = apple; } @Override public void run(){ while (true) apple.eatApple(); }}

public class Demo { public static void main(String[] args) { Apple apple = new Apple(); Producer producer = new Producer(apple,'小明'); Consumer consumer = new Consumer(apple, '小紅'); producer.start(); consumer.start(); }}

輸出結果:

小明買了5個蘋果小紅吃了1個蘋果小紅吃了1個蘋果小紅吃了1個蘋果小紅吃了1個蘋果小紅吃了1個蘋果小明買了5個蘋果小紅吃了1個蘋果 ......

到此這篇關于Java并發編程之內置鎖(synchronized)的文章就介紹到這了,更多相關Java內置鎖內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
日韩三区四区| 高清一区二区| 日韩一区二区三区精品视频第3页| 青草国产精品| 精品视频国内| 久久精品影视| 日韩欧美三区| 日韩成人三级| 蜜臀av性久久久久蜜臀aⅴ四虎| 日韩高清成人在线| 国精品产品一区| 婷婷精品视频| 青草国产精品久久久久久| 国产成人精品三级高清久久91| 伊人精品一区| 国产精品最新| 天堂资源在线亚洲| 欧美一区二区三区免费看| 日韩久久电影| 日本久久一区| 亚洲综合在线电影| 日韩午夜视频在线| 日韩免费小视频| 日韩一二三区在线观看| 亚洲伊人av| 四虎精品永久免费| 麻豆91小视频| 免费日韩视频| 国内精品亚洲| 亚洲理论在线| 久久久久久亚洲精品美女| 日韩午夜免费| 成人精品国产亚洲| 日韩激情综合| 亚洲欧洲另类| 国产精品麻豆久久| 欧美一区激情| 欧美网站在线| 久久伊人国产| 亚洲另类av| 亚洲电影在线| 精品中文字幕一区二区三区 | 电影亚洲精品噜噜在线观看 | 欧美精品三级在线| 欧美另类综合| 国产福利电影在线播放| 日本成人一区二区| 亚洲激情另类| 中文字幕一区久| 国产精品一区二区三区四区在线观看| 国产精品av一区二区| 美女av一区| 亚洲精品乱码| 一区在线免费| 欧美日韩精品在线一区| 另类小说一区二区三区| 亚洲精品免费观看| 亚洲午夜黄色| 成人亚洲一区二区| 欧美一级二级视频| 中文字幕亚洲精品乱码| 久久久国产亚洲精品| 精品免费av| 国产探花一区| 日韩精品中文字幕吗一区二区| 亚洲va在线| 免费一二一二在线视频| 国产一区二区三区黄网站| 久久精品 人人爱| 无码日韩精品一区二区免费| 亚洲免费精品| 亚洲性色视频| 99久久精品费精品国产| 成人免费网站www网站高清| 成人在线观看免费视频| 欧美黑人巨大videos精品| 青青国产精品| 亚洲18在线| 中文字幕成人| 久久午夜视频| 亚洲激情二区| 国产视频亚洲| 91久久中文| 亚洲激情av| 99综合视频| 亚洲欧美日韩精品一区二区| 99riav国产精品| 宅男噜噜噜66国产日韩在线观看| 欧美日韩国产免费观看| 制服诱惑一区二区| 午夜一级在线看亚洲| 国产色综合网| 久久xxxx| 综合激情视频| 男女性色大片免费观看一区二区| 在线国产一区| 日韩一区二区免费看| 亚洲自啪免费| 蜜臀av一区二区三区| 亚久久调教视频| 91精品国产经典在线观看| 欧美亚洲tv| 久久av导航| 激情中国色综合| 在线亚洲人成| 不卡在线一区| 久久亚洲一区| 日本aⅴ精品一区二区三区| 国产精品中文字幕亚洲欧美| 蜜桃精品视频| 福利精品一区| 久久国产中文字幕| 天堂成人国产精品一区| 亚洲久久一区| 国产精品久久国产愉拍| 精品不卡一区| 久久视频一区| 亚洲神马久久| 日韩精品三级| 精品一区二区三区亚洲 | 久久国产免费| 黑丝一区二区| 天堂va在线高清一区| 国产精品1luya在线播放| 麻豆精品一区二区综合av| 福利视频一区| 午夜精品网站| 欧美亚洲综合视频| 国产一区二区三区不卡视频网站| 日韩大片在线| 麻豆亚洲精品| 国产精品99精品一区二区三区∴| 加勒比视频一区| 国产在线欧美| 日本va欧美va欧美va精品| 国产96在线亚洲| 午夜在线播放视频欧美| 国产欧美啪啪| 99精品视频精品精品视频| 亚洲中午字幕| 久久久久亚洲精品中文字幕| 欧美日韩国产综合网| 欧美天堂一区| 欧美肉体xxxx裸体137大胆| 日韩综合一区二区| 麻豆精品久久| 亚洲在线电影| 精品在线网站观看| 亚洲一区二区毛片| 久久精品一区| 亚洲欧美高清| 高清久久精品| 亚洲美女91| 麻豆网站免费在线观看| 在线综合亚洲| 久久久91麻豆精品国产一区| 欧美va天堂在线| 国产乱码精品一区二区三区四区| 亚洲伊人av| 青草国产精品| 欧美 日韩 国产精品免费观看| 国产精品亚洲综合久久| 午夜久久免费观看| 国产精品极品国产中出| 99pao成人国产永久免费视频| 麻豆视频一区| 亚洲影院天堂中文av色| 亚洲va中文在线播放免费| 91国内精品| 欧美+日本+国产+在线a∨观看| 国产欧美日韩影院| 亚洲激情偷拍| 91综合网人人| 欧美日韩18| 一区二区视频欧美| 国产精品久久观看| 欧美精品影院| 美女久久网站| 亚洲高清二区| 精品国产精品国产偷麻豆| 综合欧美精品| 婷婷丁香综合| 国产suv精品一区| 欧美亚洲福利| 先锋亚洲精品| 日韩一区二区中文| 国产精品一区亚洲| 视频一区二区三区在线| 99成人超碰| 精品免费av一区二区三区| 婷婷亚洲成人| 在线亚洲国产精品网站| 成人欧美一区二区三区的电影| 欧美一区在线观看视频| 免费视频久久| 欧美va天堂| 成人日韩精品| 97精品视频在线看| 久久精品一区二区国产| 日韩成人午夜精品|