中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

淺談同步監視器之同步代碼塊、同步方法

發布時間:2020-10-05 17:35:07 來源:腳本之家 閱讀:390 作者:jingxian 欄目:編程語言

如果有多個線程訪問共享資源,可能會出現當一個線程沒有處理完業務,然后另一個線程進入,從而導致共享資源出現不安全的情況。

日常例子:銀行取錢,A和B有擁有同一個銀行賬戶,A用存折在柜臺取錢,B在取款機取錢。取錢有兩個關鍵步驟:

(1)判斷賬戶里的錢的余額是否大于所取錢數

(2)如果大于所取錢數,則賬戶最終所剩余額 = 余額 - 所取錢數。

如果沒有線程同步的情況下,我們假設這一種情況,這個共同的賬戶里共1000元。

(1)A B同時去取600元,A所在線程執行到上面的第一個步驟,判斷所取錢數小于現有余額,CPU時間片用完。

(2)這時B進來到第一個步驟,同樣是執行判斷,因為A只執行完第一步驟,沒有執行減法,這時現有余額還是1000元。

(3)由于在CPU分配的時間里他接著完成了減法操作。這時賬戶余額為1000 - 600 = 400。成功取出600元。

(4)最后A接著之前執行的步驟,去做減法操作, 賬戶余額為 -200 = 400 - 600。

到這里,我只想說為什么,是什么銀行可以允許你這么做, 當然,除非銀行是你家開的。

總之銀行不可能讓這種情況發生,所以我們的偉大先賢們就想到線程同步,其實很簡單,你也能想到。如果讓這兩個步驟同時完成,不可分開,問題也就迎刃而解。

下面就說到在JAVA中同步代碼的實現:

涉及概念:同步監視器,是一個普通的java對象,同一個同步監視器如果一個線程拿到,則其他線程就沒有辦法拿到。好像是一個房門里只有唯一的一把鑰匙, 不能復制。如果一個人拿著它進入房門,其他人只能在外面等候。等他出來你獲得了它,你才能進入房間。

下面的代碼如果沒有做線程同步操作(同步代碼塊、同步方法、同步鎖)結果是如下:

Thread-1------判斷所取錢數是否大于余額------
Thread-0------判斷所取錢數是否大于余額------
Thread-0======做減法操作,取出現金======
Thread-1======做減法操作,取出現金======

很顯然線程1的那兩步沒有同時完成。

下面的幾種方法可以實現兩步同時完成。

1、同步代碼塊:

public class ThreadTest {

  public static void main(String[] args){
Thread t1 = new Thread1(); //線程1
Thread t2 = new Thread1();//線程2
t1.start();
t2.start();
  }
}

class Thread1 extends Thread{

  @Override
  public void run() {
super.run();
try {

  BeTested b = new BeTested(); // 這地方,因為這個例子中同步監視器 obj 是線程共享的,兩個線程用兩個不同的對象,也沒有關系,不影響結果。
  b.beTested(this);
} catch (InterruptedException e) {
  e.printStackTrace();
}
  }
}

class BeTested {
  static Object obj = new Object();;
  public void beTested(Thread t) throws InterruptedException{
synchronized (obj) { // obj 為同步監視器
  System.out.println(t.getName() + "------判斷所取錢數是否大于余額------");
  t.sleep(1000); // 如果沒有同步這樣能理明顯地看到這兩步驟不能在一個線程,同一個時間片里執行完成。
  System.out.println(t.getName() + "======做減法操作,取出現金======");
}
  }
}

執行結果如下:

Thread-0------判斷所取錢數是否大于余額------
Thread-0======做減法操作,取出現金======
Thread-1------判斷所取錢數是否大于余額------
Thread-1======做減法操作,取出現金======

注意:同步監視器對象的選用很關鍵。要選擇線程共享的對象,比如上面例子的 obj, 它是static修飾的才行,如果沒有static修飾,則是使用不同的同步監視器(不是同一個對象),相當于是兩把鑰匙。

  (如果obj = "aaaa" 沒有static修飾也可以實現同步,那是因為這個obj引用的常量池里的同一個string對象,強烈不推薦使用)

2、同步方法(非靜態方法)

把上面的那兩類改成如下,main方法所在類不變。

class Thread1 extends Thread{

  static BeTested b = new BeTested(); // 在這種方法中,這里必須是同個對象(static修飾),下文會詳細說明
  @Override
  public void run() {
super.run();
try {
  b.beTested(this);
} catch (InterruptedException e) {
  e.printStackTrace();
}
  }
}

class BeTested {
  static Object obj = new Object();;
  public synchronized void beTested(Thread t) throws InterruptedException{
  System.out.println(t.getName() + "------判斷所取錢數是否大于余額------");
  t.sleep(1000); 
  System.out.println(t.getName() + "======做減法操作,取出現金======");
  }
}

執行結果如下:

Thread-0------判斷所取錢數是否大于余額------
Thread-0======做減法操作,取出現金======
Thread-1------判斷所取錢數是否大于余額------
Thread-1======做減法操作,取出現金======

注意:因為同步方法中,所用的同步監視器不能指定,默認使用的調用該方法的對象,也就是this。所以 Thread1 類中相對于示例1中同步代碼塊中修改的部分, 也是要static修飾。也就是說要使用同一個對象。

3、同步方法(靜態方法)

把上面的那兩類改成如下,main方法所在類不變。

class Thread1 extends Thread{

  @Override
  public void run() {
super.run();
try {
  BeTested b = new BeTested(); // 這里每個線程使用不同的對象。
  b.beTested(this);
} catch (InterruptedException e) {
  e.printStackTrace();
}
  }
}

class BeTested {
  static Object obj = new Object();;
  public static synchronized void beTested(Thread t) throws InterruptedException{
  System.out.println(t.getName() + "------判斷所取錢數是否大于余額------");
  t.sleep(1000); 
  System.out.println(t.getName() + "======做減法操作,取出現金======");
  }
}

執行結果如下:

Thread-0------判斷所取錢數是否大于余額------
Thread-0======做減法操作,取出現金======
Thread-1------判斷所取錢數是否大于余額------
Thread-1======做減法操作,取出現金======

注意:因為同步靜態方法中,同步監視器是這個類而不是這個類的對象。所以Thread1 類中相對于示例2中同步代碼塊中修改的部分,不須要用static修飾,不是同一個對象也沒關系。因為這個類他本身就是共享的。

總結:如上幾種方式進行線程同步處理時,要注意你所使用的同步監視器對象,它必須是共享的。

注:還有使用同步鎖的方式實現線程同步,本篇文章不做討論。

以上這篇淺談同步監視器之同步代碼塊、同步方法就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

信丰县| 西乌珠穆沁旗| 汉源县| 天全县| 射洪县| 竹北市| 西贡区| 云林县| 廉江市| 宜昌市| 高淳县| 富川| 咸丰县| 鸡西市| 乌苏市| 枝江市| 寿阳县| 凤凰县| 安平县| 宜良县| 桦南县| 易门县| 彰化市| 阿克| 镶黄旗| 武夷山市| 探索| 沅陵县| 滨州市| 安庆市| 正镶白旗| 阿拉善左旗| 称多县| 黎平县| 崇仁县| 嘉义县| 石阡县| 夏津县| 丘北县| 新化县| 隆子县|