国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Java多線程(二)同步與等待喚醒

2019-11-15 01:08:56
字體:
來源:轉載
供稿:網友
java多線程(二)同步與等待喚醒

1:數據安全問題

1.1:什么情況下會出現數據安全問題?

多個線程對同一個資源進行操作,并且操作資源的語句有多條。那么這個時候這些語句因為cpu的隨機性,有可能被多個線程分開執行。導致數據安全問題。

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

 1 public class SaveMoneyDemo1 { 2      3     public static void main(String[] args) { 4         SaveDemo1 s = new SaveDemo1(); 5         Thread t1 = new Thread(s); 6         t1.setName("老爸"); 7         Thread t2 = new Thread(s); 8         t2.setName("老媽"); 9         Thread t3 = new Thread(s);10         t3.setName("姐姐");11         t1.start();12         t2.start();13         t3.start();14     }15 16 }17 18 class SaveDemo1 implements Runnable{19     PRivate int sum = 0;20     //要執行的代碼塊放在run方法里面。21     public void run() {22         //每個人能存三次,就是循環三遍23         for(int i=0; i<3; i++){24             sum+=100;25             System.out.println(Thread.currentThread().getName()+"給你匯了100,目前賬號共有 "+sum+" 元");26                     27         }28     }29 }30 /**31  * 執行結果:32         老媽給你匯了100,目前賬號共有 200 元33         老媽給你匯了100,目前賬號共有 400 元34         老媽給你匯了100,目前賬號共有 500 元35         姐姐給你匯了100,目前賬號共有 300 元36         姐姐給你匯了100,目前賬號共有 600 元37         姐姐給你匯了100,目前賬號共有 700 元38         老爸給你匯了100,目前賬號共有 200 元39         老爸給你匯了100,目前賬號共有 800 元40         老爸給你匯了100,目前賬號共有 900 元41  * 42  */
沒有同步的匯款代碼

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

1.2:解決方案: 同步機制

1.2.1:同步代碼塊。

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

對同一個資源的操作語句。

}

1.2.2:同步方法的鎖:

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

2.2:靜態同步方法-----字節碼文件對象。類名.class

 1 public class SaveMoneyDemo2 { 2      3     public static void main(String[] args) { 4         SaveDemo2 s = new SaveDemo2(); 5         Thread t1 = new Thread(s); 6         t1.setName("老爸"); 7         Thread t2 = new Thread(s); 8         t2.setName("老媽"); 9         Thread t3 = new Thread(s);10         t3.setName("姐姐");11         t1.start();12         t2.start();13         t3.start();14     }15 16 }17 18 class SaveDemo2 implements Runnable{19     private int sum = 0;20     //要執行的代碼塊放在run方法里面。21     public void run() {22         //每個人能存三次,就是循環三遍23         synchronized(this){24             for(int i=0; i<3; i++){25                 sum+=100;26                 System.out.println(Thread.currentThread().getName()+"給你匯了100,目前賬號共有 "+sum+" 元");27             }28         }29     }30 }
使用同步的數據安全的匯款

1.3:如果加了同步,還出現數據安全問題,如何排查?

1.3.1:是否為同一把鎖

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

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

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

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

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

 1 public class DeadLockDemo1 { 2     public static void main(String[] args) { 3         Thread t1 = new Customer1(); 4         Thread t2 = new Seller1(); 5         t1.start(); 6         t2.start(); 7     } 8 } 9 10 class Customer1 extends Thread{11     public static Object money = new Object();12     @Override13     public void run() {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 extends Thread{26     public static Object goods = new Object();27     @Override28     public void run() {29         //商家有貨30         synchronized (goods) {31             System.out.println("商家等客戶給錢");32             //商家等錢33             synchronized (Customer1.money) {34                 System.out.println("商家給客戶貨");35             }36         }37     }38 }39 40 /**41  * 如果想結果暴露地更明顯,可以使用sleep()方法42  * 運行死鎖的結果:43  *     客戶等商家給貨44  *    商家等客戶給錢45  * 46  */
死鎖示例代碼

3:等待喚醒機制。

前面多個線程案例中,每個線程執行的操作是一樣的。如果線程所執行的操作不一樣呢?比如一個線程負責生產產品,另外一個線程負責消費產品。

3.1:創建2個線程,2個線程的動作是不一樣。比如說:一個生產者和一個消費者。

需求:生產者生產一個產品。消費者消費一個產品。這就涉及到了等待喚醒機制。當生產者生產一個產品后進入等待模式等待消費者來消費這個產品,當消費者消費了這個產品,發現沒有產品了,消費者等待,叫生產者生產產品。生產者生產了產品則通知消費者。這就涉及到等待喚醒機制。

3.2:等待喚醒機制。

等待喚醒機制必須是在同步中進行,因為等待和喚醒都是要通過鎖來操作的,查看API就是的,wait()和notify()是屬于Object的方法,任何對象都是可以作為鎖的。

wait:讓當前線程等待。在哪里等待的就在哪里醒過來。

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

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

wait和sleep的區別:

1:sleep會擁有鎖,而wait會釋放鎖。

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

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

3.3:一個生產者和一個消費者的代碼實現

 1 /* 2  * 生產者生產一個產品。 3  * 消費者消費一個產品。 4  * 生產者可以生產多個產品,但是一次只能生產一個產品。消費了才能生產。 5  * 消費者可以消費多個產品。但是一次只能消費一個 產品。生產有了產品才能消費。 6  */ 7 public class ProCusDemo1 { 8     public static Object lock = new Object();//創建一個對象作為鎖 9     public static int num = 0;//產品數10     public static void main(String[] args) {11         Pro pro = new Pro();12         Cus cus = new Cus();13         pro.start();14         cus.start();15     }16     17 }18 19 class Pro extends Thread {20     @Override21     public void run() {22         //不斷生產,使用循環23         while(true){24             try {25                 Thread.sleep(100);26             } catch (InterruptedException e1) {27                 // TODO Auto-generated catch block28                 e1.printStackTrace();29             }30 //            System.out.println("111");31             //操作同一數據——產品數(num),使用同步代碼塊,也可以是等待喚醒機制必須在同步在同步中進行32             synchronized (ProCusDemo1.lock) {33                 //當有一個產品了,生產者就不用生產了34                 if(ProCusDemo1.num == 1){35                     try {36                         //不用生產的體現就是等待37                         ProCusDemo1.lock.wait();38 //                        System.out.println("222");39                     } catch (InterruptedException e) {40                         e.printStackTrace();41                     }42                 }43                 ProCusDemo1.num ++;//生產了一個產品44                 System.out.println("生產者生產了一個產品,現有:"+ProCusDemo1.num+" 個");45                 //當生產了一個產品之后就可以喚醒消費者消費了46                 ProCusDemo1.lock.notify();47             }48         }49     }50 }51 52 class Cus extends Thread {53     @Override54     public void run() {55         while(true){56 //            System.out.println("333");57             try {58                 Thread.sleep(100);59             } catch (InterruptedException e1) {60                 // TODO Auto-generated catch block61                 e1.printStackTrace();62             }63             //多個線程操作同一數據使用同步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("消費者消費了一個產品,現有:"+ProCusDemo1.num+" 個");75                 ProCusDemo1.lock.notify();76             }77         }78         79     }80 }
等待喚醒機制——生產消費


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 凤庆县| 浠水县| 会理县| 云林县| 霍州市| 中宁县| 建水县| 嘉峪关市| 昭苏县| 承德市| 揭阳市| 舞阳县| 横山县| 邛崃市| 凯里市| 玛纳斯县| 揭阳市| 武夷山市| 渭南市| 姚安县| 泸定县| 汉寿县| 阿坝| 涡阳县| 黄大仙区| 新田县| 安化县| 增城市| 城市| 望奎县| 湘乡市| 年辖:市辖区| 门头沟区| 丰城市| 资阳市| 汕尾市| 连云港市| 阜南县| 天峻县| 安溪县| 镇巴县|