日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

java不同进程的相互唤醒_Java多线程(二)同步与等待唤醒

發(fā)布時(shí)間:2024/7/23 java 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java不同进程的相互唤醒_Java多线程(二)同步与等待唤醒 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1:數(shù)據(jù)安全問題

1.1:什么情況下會(huì)出現(xiàn)數(shù)據(jù)安全問題?

多個(gè)線程對(duì)同一個(gè)資源進(jìn)行操作,并且操作資源的語句有多條。那么這個(gè)時(shí)候這些語句因?yàn)閏pu的隨機(jī)性,有可能被多個(gè)線程分開執(zhí)行。導(dǎo)致數(shù)據(jù)安全問題。

例子:有3個(gè)人分別是你爸、你媽媽、你姐,去你的一個(gè)賬戶匯錢給你,每一個(gè)只能存3次,一次只能存100元。每存一次,請(qǐng)打顯示出賬戶里的余額。代碼體現(xiàn):

1 public classSaveMoneyDemo1 {2

3 public static voidmain(String[] args) {4 SaveDemo1 s = newSaveDemo1();5 Thread t1 = newThread(s);6 t1.setName("老爸");7 Thread t2 = newThread(s);8 t2.setName("老媽");9 Thread t3 = newThread(s);10 t3.setName("姐姐");11 t1.start();12 t2.start();13 t3.start();14 }15

16 }17

18 class SaveDemo1 implementsRunnable{19 private int sum = 0;20 //要執(zhí)行的代碼塊放在run方法里面。

21 public voidrun() {22 //每個(gè)人能存三次,就是循環(huán)三遍

23 for(int i=0; i<3; i++){24 sum+=100;25 System.out.println(Thread.currentThread().getName()+"給你匯了100,目前賬號(hào)共有 "+sum+" 元");26

27 }28 }29 }30 /**

31 * 執(zhí)行結(jié)果:32 老媽給你匯了100,目前賬號(hào)共有 200 元33 老媽給你匯了100,目前賬號(hào)共有 400 元34 老媽給你匯了100,目前賬號(hào)共有 500 元35 姐姐給你匯了100,目前賬號(hào)共有 300 元36 姐姐給你匯了100,目前賬號(hào)共有 600 元37 姐姐給你匯了100,目前賬號(hào)共有 700 元38 老爸給你匯了100,目前賬號(hào)共有 200 元39 老爸給你匯了100,目前賬號(hào)共有 800 元40 老爸給你匯了100,目前賬號(hào)共有 900 元41 *42 */

沒有同步的匯款代碼

運(yùn)行結(jié)果好喜感。為什么會(huì)出現(xiàn)這種情況?分析:這三人存款是不需按照順序和次數(shù)的,反正幫你存夠三次就行了,所以用多線程更為合理。可是,打個(gè)比方:當(dāng)你媽媽在存錢的時(shí)候錢是存進(jìn)去了,在沒來得及顯示余額的時(shí)候你爸正好也把錢存了進(jìn)去,這時(shí)候總金額連同你媽和你爸的加在一起了!所以顯示出的金額會(huì)發(fā)生這樣的情況。那么如何解決類似的情況呢?這就要限定一個(gè)人存一次就先把金額加上,不能讓多人存完之后再一起加,如果這樣那金額的顯示就亂套了。這時(shí)候就要使用同步機(jī)制了。

1.2:解決方案: 同步機(jī)制

1.2.1:同步代碼塊。

synchronized(鎖){//鎖可以為任意對(duì)象。但是需要保證多個(gè)線程用的是同一把鎖。

對(duì)同一個(gè)資源的操作語句。

}

1.2.2:同步方法的鎖:

2.1:同步方法-----this

2.2:靜態(tài)同步方法-----字節(jié)碼文件對(duì)象。類名.class

1 public classSaveMoneyDemo2 {2

3 public static voidmain(String[] args) {4 SaveDemo2 s = newSaveDemo2();5 Thread t1 = newThread(s);6 t1.setName("老爸");7 Thread t2 = newThread(s);8 t2.setName("老媽");9 Thread t3 = newThread(s);10 t3.setName("姐姐");11 t1.start();12 t2.start();13 t3.start();14 }15

16 }17

18 class SaveDemo2 implementsRunnable{19 private int sum = 0;20 //要執(zhí)行的代碼塊放在run方法里面。

21 public voidrun() {22 //每個(gè)人能存三次,就是循環(huán)三遍

23 synchronized(this){24 for(int i=0; i<3; i++){25 sum+=100;26 System.out.println(Thread.currentThread().getName()+"給你匯了100,目前賬號(hào)共有 "+sum+" 元");27 }28 }29 }30 }

使用同步的數(shù)據(jù)安全的匯款

1.3:如果加了同步,還出現(xiàn)數(shù)據(jù)安全問題,如何排查?

1.3.1:是否為同一把鎖

1.3.2:訪問資源的多條語句是否在同步中。

1.4:關(guān)于同步的拙劣理解:一件事先一口氣做完!不讓別人插手。(好像太牽強(qiáng)了)

2:死鎖問題——互不釋放資源(互相等待資源)

2.1  需求:用程序來描述以下情況:一手交錢一手交貨。商家與顧客兩人都是很小氣的人,顧客買商家的東西,商家收顧客的前,顧客說:先給我貨我再給你錢;商家說:先給我錢我再給你貨。最好的結(jié)局就是各自得到各自的東西。

2.2  分析:對(duì)于商家和客戶來說和他們倆有關(guān)的不是錢就是貨,而限制這兩人的也就是錢和貨。這樣一來錢和貨就可以看做是程序中的兩個(gè)鎖了。造成死鎖的原因:同步代碼嵌套!在平時(shí)開發(fā)時(shí)應(yīng)避免同步嵌套!

1 public classDeadLockDemo1 {2 public static voidmain(String[] args) {3 Thread t1 = newCustomer1();4 Thread t2 = newSeller1();5 t1.start();6 t2.start();7 }8 }9

10 class Customer1 extendsThread{11 public static Object money = newObject();12 @Override13 public voidrun() {14 //客戶有錢

15 synchronized(money){16 System.out.println("客戶等商家給貨");17 //客戶等貨

18 synchronized(Seller1.goods) {19 System.out.println("客戶給商家錢");20 }21 }22 }23 }24

25 class Seller1 extendsThread{26 public static Object goods = newObject();27 @Override28 public voidrun() {29 //商家有貨

30 synchronized(goods) {31 System.out.println("商家等客戶給錢");32 //商家等錢

33 synchronized(Customer1.money) {34 System.out.println("商家給客戶貨");35 }36 }37 }38 }39

40 /**

41 * 如果想結(jié)果暴露地更明顯,可以使用sleep()方法42 * 運(yùn)行死鎖的結(jié)果:43 * 客戶等商家給貨44 * 商家等客戶給錢45 *46 */

死鎖示例代碼

3:等待喚醒機(jī)制。

前面多個(gè)線程案例中,每個(gè)線程執(zhí)行的操作是一樣的。如果線程所執(zhí)行的操作不一樣呢?比如一個(gè)線程負(fù)責(zé)生產(chǎn)產(chǎn)品,另外一個(gè)線程負(fù)責(zé)消費(fèi)產(chǎn)品。

3.1:創(chuàng)建2個(gè)線程,2個(gè)線程的動(dòng)作是不一樣。比如說:一個(gè)生產(chǎn)者和一個(gè)消費(fèi)者。

需求:生產(chǎn)者生產(chǎn)一個(gè)產(chǎn)品。消費(fèi)者消費(fèi)一個(gè)產(chǎn)品。這就涉及到了等待喚醒機(jī)制。當(dāng)生產(chǎn)者生產(chǎn)一個(gè)產(chǎn)品后進(jìn)入等待模式等待消費(fèi)者來消費(fèi)這個(gè)產(chǎn)品,當(dāng)消費(fèi)者消費(fèi)了這個(gè)產(chǎn)品,發(fā)現(xiàn)沒有產(chǎn)品了,消費(fèi)者等待,叫生產(chǎn)者生產(chǎn)產(chǎn)品。生產(chǎn)者生產(chǎn)了產(chǎn)品則通知消費(fèi)者。這就涉及到等待喚醒機(jī)制。

3.2:等待喚醒機(jī)制。

等待喚醒機(jī)制必須是在同步中進(jìn)行,因?yàn)榈却蛦拘讯际且ㄟ^鎖來操作的,查看API就是的,wait()和notify()是屬于Object的方法,任何對(duì)象都是可以作為鎖的。

wait:讓當(dāng)前線程等待。在哪里等待的就在哪里醒過來。

notify() :喚醒其中一個(gè)等待的線程。

notifyAll():喚醒所有等待的線程

wait和sleep的區(qū)別:

1:sleep會(huì)擁有鎖,而wait會(huì)釋放鎖。

2:sleep睡眠的時(shí)間是固定的,而wait等待的時(shí)間是不固定的。

3:sleep可以放在同步中,也可以不放在同步中。wait方法必須放在同步中。

3.3:一個(gè)生產(chǎn)者和一個(gè)消費(fèi)者的代碼實(shí)現(xiàn)

1 /*

2 * 生產(chǎn)者生產(chǎn)一個(gè)產(chǎn)品。3 * 消費(fèi)者消費(fèi)一個(gè)產(chǎn)品。4 * 生產(chǎn)者可以生產(chǎn)多個(gè)產(chǎn)品,但是一次只能生產(chǎn)一個(gè)產(chǎn)品。消費(fèi)了才能生產(chǎn)。5 * 消費(fèi)者可以消費(fèi)多個(gè)產(chǎn)品。但是一次只能消費(fèi)一個(gè) 產(chǎn)品。生產(chǎn)有了產(chǎn)品才能消費(fèi)。6 */

7 public classProCusDemo1 {8 public static Object lock = new Object();//創(chuàng)建一個(gè)對(duì)象作為鎖

9 public static int num = 0;//產(chǎn)品數(shù)

10 public static voidmain(String[] args) {11 Pro pro = newPro();12 Cus cus = newCus();13 pro.start();14 cus.start();15 }16

17 }18

19 class Pro extendsThread {20 @Override21 public voidrun() {22 //不斷生產(chǎn),使用循環(huán)

23 while(true){24 try{25 Thread.sleep(100);26 } catch(InterruptedException e1) {27 //TODO Auto-generated catch block

28 e1.printStackTrace();29 }30 //System.out.println("111");31 //操作同一數(shù)據(jù)——產(chǎn)品數(shù)(num),使用同步代碼塊,也可以是等待喚醒機(jī)制必須在同步在同步中進(jìn)行

32 synchronized(ProCusDemo1.lock) {33 //當(dāng)有一個(gè)產(chǎn)品了,生產(chǎn)者就不用生產(chǎn)了

34 if(ProCusDemo1.num == 1){35 try{36 //不用生產(chǎn)的體現(xiàn)就是等待

37 ProCusDemo1.lock.wait();38 //System.out.println("222");

39 } catch(InterruptedException e) {40 e.printStackTrace();41 }42 }43 ProCusDemo1.num ++;//生產(chǎn)了一個(gè)產(chǎn)品

44 System.out.println("生產(chǎn)者生產(chǎn)了一個(gè)產(chǎn)品,現(xiàn)有:"+ProCusDemo1.num+" 個(gè)");45 //當(dāng)生產(chǎn)了一個(gè)產(chǎn)品之后就可以喚醒消費(fèi)者消費(fèi)了

46 ProCusDemo1.lock.notify();47 }48 }49 }50 }51

52 class Cus extendsThread {53 @Override54 public voidrun() {55 while(true){56 //System.out.println("333");

57 try{58 Thread.sleep(100);59 } catch(InterruptedException e1) {60 //TODO Auto-generated catch block

61 e1.printStackTrace();62 }63 //多個(gè)線程操作同一數(shù)據(jù)使用同步

64 synchronized(ProCusDemo1.lock) {65 if(ProCusDemo1.num == 0){66 try{67 ProCusDemo1.lock.wait();68 //System.out.println("444");

69 } catch(InterruptedException e) {70 e.printStackTrace();71 }72 }73 ProCusDemo1.num--;74 System.out.println("消費(fèi)者消費(fèi)了一個(gè)產(chǎn)品,現(xiàn)有:"+ProCusDemo1.num+" 個(gè)");75 ProCusDemo1.lock.notify();76 }77 }78

79 }80 }

等待喚醒機(jī)制——生產(chǎn)消費(fèi)

總結(jié)

以上是生活随笔為你收集整理的java不同进程的相互唤醒_Java多线程(二)同步与等待唤醒的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。