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

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

java線程簡(jiǎn)介(同步詳細(xì)信息)

2019-11-18 10:47:05
字體:
供稿:網(wǎng)友

  1、互斥
  
  
  在共享對(duì)數(shù)據(jù)的訪問中,我們討論了 synchronized 塊的特征,并在實(shí)現(xiàn)典型互斥鎖(即,互斥或臨界段)時(shí)說明了它們,其中每次只有一個(gè)線程可以執(zhí)行受給定鎖保護(hù)的代碼塊。
  
  互斥是同步所做工作的重要部分,但同步還有其它幾種特征,這些特征對(duì)于在多處理器系統(tǒng)上取得正確結(jié)果非常重要。
  
  2、可見性
  
  
  除了互斥,同步(如 volatile)強(qiáng)制某些可見性約束。當(dāng)對(duì)象獲取鎖時(shí),它首先使自己的高速緩存無效,這樣就可以保證直接從主內(nèi)存中裝入變量。
  
  同樣,在對(duì)象釋放鎖之前,它會(huì)刷新其高速緩存,強(qiáng)制使已做的任何更改都出現(xiàn)在主內(nèi)存中。
  
  這樣,會(huì)保證在同一個(gè)鎖上同步的兩個(gè)線程看到在 synchronized 塊內(nèi)修改的變量的相同值。
  
  
  3、什么時(shí)候必須同步?
  
  
  要跨線程維護(hù)正確的可見性,只要在幾個(gè)線程之間共享非 final 變量,就必須使用 synchronized(或 volatile)以確保一個(gè)線程可以看見另一個(gè)線程做的更改。
  
  可見性同步的基本規(guī)則是在以下情況中必須同步:
  
  讀取上一次可能是由另一個(gè)線程寫入的變量
  寫入下一次可能由另一個(gè)線程讀取的變量
  
  4、用于一致性的同步
  
  
  除了用于可見性的同步,從應(yīng)用程序角度看,您還必須用同步來確保一致性得到了維護(hù)。當(dāng)修改多個(gè)相關(guān)值時(shí),您想要其它線程原子地看到這組更改 — 要么看到全部更改,要么什么也看不到。這適用于相關(guān)數(shù)據(jù)項(xiàng)(如粒子的位置和速率)和元數(shù)據(jù)項(xiàng)(如鏈表中包含的數(shù)據(jù)值和列表自身中的數(shù)據(jù)項(xiàng)的鏈)。
  
  考慮以下示例,它實(shí)現(xiàn)了一個(gè)簡(jiǎn)單(但不是線程安全的)的整數(shù)堆棧:
  
  
  public class UnsafeStack {
   public int top = 0;
   public int[] values = new int[1000];
  
   public void push(int n) {
   values[top++] = n;
   }
  
   public int pop() {
   return values[--top];
   }
  }
  
  5、遞增共享計(jì)數(shù)器
  
  
  通常,假如正在保護(hù)一個(gè)基本變量(如一個(gè)整數(shù)),有時(shí)只使用 volatile 就可以僥幸過關(guān)。但是,假如變量的新值派生自以前的值,就必須使用同步。為什么?考慮這個(gè)類:
  
  
  public class Counter {
   PRivate int counter = 0;
  
   public int get() { return counter; }
   public void set(int n) { counter = n; }
   public void increment() {
   set(get() + 1);
   }
  }
  
  
  當(dāng)我們要遞增計(jì)數(shù)器時(shí),會(huì)發(fā)生什么?請(qǐng)看 increment() 的代碼。它很清楚,但不是線程安全的。假如兩個(gè)線程試圖同時(shí)執(zhí)行 increment(),會(huì)發(fā)生什么?計(jì)數(shù)器也許會(huì)增加 1,也許增加 2。令人驚異的是,把 counter 標(biāo)記成 volatile 沒有幫助,使 get() 和 set() 都變成 synchronized 也沒有幫助。
  
  設(shè)想計(jì)數(shù)器是零,而兩個(gè)線程同時(shí)執(zhí)行遞增操作代碼。這兩個(gè)線程會(huì)調(diào)用 Counter.get(),并且看到計(jì)數(shù)器是零。現(xiàn)在兩個(gè)線程都對(duì)它加一,然后調(diào)用 Counter.set()。假如我們的計(jì)時(shí)不太湊巧,那么這兩個(gè)線程都看不到對(duì)方的更新,即使 counter 是 volatile,或者 get() 和 set() 是 synchronized。現(xiàn)在,即使計(jì)數(shù)器遞增了兩次,得到的值也許只是一,而不是二。
  
  要使遞增操作正確運(yùn)行,不僅 get() 和 set() 必須是 synchronized,而且 increment() 也必需是 synchronized!否則,調(diào)用 increment() 的線程可能會(huì)中斷另一個(gè)調(diào)用 increment() 的線程。假如您不走運(yùn),最終結(jié)果將會(huì)是計(jì)數(shù)器只增加了一次,不是兩次。同步 increment() 防止了這種情況的發(fā)生,因?yàn)檎麄€(gè)遞增操作是原子的。
  
  當(dāng)循環(huán)遍歷 Vector 的元素時(shí),同樣如此。即使同步了 Vector 的方法,但在循環(huán)遍歷時(shí),Vector 的內(nèi)容仍然會(huì)更改。假如要確保 Vector 的內(nèi)容在循環(huán)遍歷時(shí)不更改,必須同步整個(gè)代碼塊。
  
  6、不變性和 final 字段
  
  
  許多 java 類,包括 String、Integer 和 BigDecimal,都是不可改變的:一旦構(gòu)造之后,它們的狀態(tài)就永遠(yuǎn)不會(huì)更改。假如某個(gè)類的所有字段都被聲明成 final,那么這個(gè)類就是不可改變的。(實(shí)際上,許多不可改變的類都有非 final 字段,用于高速緩存以前計(jì)算的方法結(jié)果,如 String.hashCode(),但調(diào)用者看不到這些字段。)
  
  不可改變的類使并發(fā)編程變得非常簡(jiǎn)單。因?yàn)椴荒芨乃鼈兊淖侄危跃筒恍枰獡?dān)心把狀態(tài)的更改從一個(gè)線程傳遞到另一個(gè)線程。在正確構(gòu)造了對(duì)象之后,可以把它看作是常量。
  
  同樣,final 字段對(duì)于線程也更友好。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 洛扎县| 根河市| 远安县| 若尔盖县| 红原县| 寿光市| 平山县| 灌云县| 乌兰察布市| 马山县| 漳平市| 永昌县| 永泰县| 会理县| 金秀| 大洼县| 邵阳市| 庄浪县| 松阳县| 鹤庆县| 隆安县| 新密市| 平武县| 舟曲县| 海口市| 洪湖市| 莒南县| 延寿县| 宁河县| 伊宁县| 龙山县| 昭苏县| 嵊州市| 静海县| 汶上县| 梓潼县| 高安市| 逊克县| 睢宁县| 海林市| 麻栗坡县|