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

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

JavaThread應該注意的問題

2019-11-18 11:13:07
字體:
來源:轉載
供稿:網友

  java的線程編程非常簡單。但有時會看到一些關于線程的錯誤用法。下面列出一些應該注重的問題。
  
  1.同步對象的恒定性
  All java objects are references.
  
  對于局部變量和參數來說,java里面的int, float, double, boolean等基本數據類型,都在棧上。這些基本類型是無法同步的;java里面的對象(根對象是Object),全都在堆里,指向對象的reference在棧上。
  
  java中的同步對象,實際上是對于reference所指的“對象地址”進行同步。
  需要注重的問題是,千萬不要對同步對象重新賦值。舉個例子。
  class A implements Runnable{
  Object lock = new Object();
  
  void run(){
  for(...){
  synchronized(lock){
  // do something
  ...
  lock = new Object();
  }
  }
  }
  
  run函數里面的這段同步代碼實際上是毫無意義的。因為每一次lock都給重新分配了新的對象的reference,每個線程都在新的reference同步。
  大家可能覺得希奇,怎么會舉這么一個例子。因為我見過這樣的代碼,同步對象在其它的函數里被重新賦了新值。
  這種問題很難查出來。
  所以,一般應該把同步對象聲明為final.
  final Object lock = new Object();
  
  
  
  使用Singleton Pattern 設計模式來獲取同步對象,也是一種很好的選擇。
  
  2.如何放置共享數據
  實現線程,有兩種方法,一種是繼續Thread類,一種是實現Runnable接口。
  
  上面舉的例子,采用實現Runnable接口的方法。本文推薦這種方法。
  
  首先,把需要共享的數據放在一個實現Runnable接口的類里面,然后,把這個類的實例傳給多個Thread的構造方法。這樣,新創建的多個Thread,都共同擁有一個Runnable實例,共享同一份數據。
  
  假如采用繼續Thread類的方法,就只好使用static靜態成員了。假如共享的數據比較多,就需要大量的static靜態成員,令程序數據結構混亂,難以擴展。這種情況應該盡量避免。
  
  編寫一段多線程代碼,處理一個稍微復雜點的問題。兩種方法的優劣,一試便知。
  
  3.同步的粒度
  線程同步的粒度越小越好,即,線程同步的代碼塊越小越好。盡量避免用synchronized修飾符來聲明方法。盡量使用synchronized(anObject)的方式,假如不想引入新的同步對象,使用synchronized(this)的方式。而且,synchronized代碼塊越小越好。
  
  4.線程之間的通知
  這里使用“通知”這個詞,而不用“通信”這個詞,是為了避免詞義的擴大化。
  
  線程之間的通知,通過Object對象的wait()和notify() 或notifyAll() 方法實現。
  
  下面用一個例子,來說明其工作原理:
  
  假設有兩個線程,A和B。共同擁有一個同步對象,lock。
  
  1.首先,線程A通過synchronized(lock) 獲得lock同步對象,然后調用lock.wait()函數,放棄lock同步對象,線程A停止運行,進入等待隊列。
  
  2.線程B通過synchronized(lock) 獲得線程A放棄的lock同步對象,做完一定的處理,然后調用 lock.notify() 或者lock.notifyAll() 通知等待隊列里面的線程A。
  
  3.線程A從等待隊列里面出來,進入ready隊列,等待調度。
  
  4.線程B繼續處理,出了synchronized(lock)塊之后,放棄lock同步對象。
  
  5.線程A獲得lock同步對象,繼續運行。
  
  
  
  例子代碼如下:
  
  public class SharedResource implements Runnable{
  
  Object lock = new Object();
  
  
  
  public void run(){
  
  // 獲取當前線程的名稱。
  
  String threadName = Thread.currentThread().getName();
  
  
  
  if( “A”.equals(threadName)){
  
  synchronized(lock){ //線程A通過synchronized(lock) 獲得lock同步對象
  
  try{
  
  System.out.PRintln(“ A gives up lock.”);
  
  lock.wait(); // 調用lock.wait()函數,放棄lock同步對象,
  
  // 線程A停止運行,進入等待隊列。
  
  }catch(InterruptedException e){
  
  }
  
  
  
  // 線程A重新獲得lock同步對象之后,繼續運行。
  
  System.out.println(“ A got lock again and continue to run.”);
  
  } // end of synchronized(lock)
  
  }
  
  
  
  if( “B”.equals(threadName)){
  
  synchronized(lock){//線程B通過synchronized(lock) 獲得線程A放棄的lock同步對象
  
  System.out.println(“B got lock.”);
  
  
  
  lock.notify(); //通知等待隊列里面的線程A,進入ready隊列,等待調度。
  
  
  
  //線程B繼續處理,出了synchronized(lock)塊之后,放棄lock同步對象。
  
  System.out.println(“B gives up lock.”);
  
  } // end of synchronized(lock)
  
  
  
  boolean hasLock = Thread.holdsLock(lock); // 檢查B是否擁有lock同步對象。
  
  System.out.println(“B has lock ? -- ” +hasLock); // false.
  
  }
  
  }
  
  }
  
  
  
  public class TestMain{
  
  public static void main(){
  
  Runnable resource = new SharedResource();
  
  
  
  Thread A = new Thread(resource,”A”);
  
  A.start();
  
  
  
  // 強迫主線程停止運行,以便線程A開始運行。
  
    try {
  
  Thread.sleep(500);
  
  }catch(InterruptedException e){
  
  }
  
  
  
  Thread B = new Thread(resource,”B”);
  
  B.start();
  
  }
  
  }
  
  
  
  5.跨類的同步對象
  對于簡單的問題,可以把訪問共享資源的同步代碼都放在一個類里面。
  
  但是對于復雜的問題,我們需要把問題分為幾個部分來處理,需要幾個不同的類來處理問題。這時,就需要在不同的類中,共享同步對象。比如,在生產者和消費者之間共享同步對象,在讀者和寫者之間共享同步對象。
  
  如何在不同的類中,共享同步對象。有幾種方法實現,
  
  (1)前面講過的方法,使用static靜態成員,(或者使用Singleton Pattern.)
  
  (2)用參數傳遞的方法,把同步對象傳遞給不同的類。
  
  (3)利用字符串常量的“原子性”。
  
  
  
  對于第三種方法,這里做一下解釋。一般來說,程序代碼中的字符串常量經過編譯之后,都具有唯一性,即,內存中不會存在兩份相同的字符串常量。
  
  (通常情況下,C++,C語言程序編譯之后,也具有同樣的特性。)
  
  比如,我們有如下代碼。
  
  String A = “atom”;
  
  String B = “atom”;
  
  我們有理由認為,A和B指向同一個字符串常量。即,A==B。
  
  注重,聲明字符串變量的代碼,不符合上面的規則。
  
  String C= new String(“atom”);
  
  String D = new String(“atom”);
  
  這里的C和D的聲明是字符串變量的聲明,所以,C != D。
  
  
  
  有了上述的熟悉,我們就可以使用字符串常量作為同步對象。
  
  比如我們在不同的類中,使用synchronized(“myLock”), “myLock”.wait(),“myLock”.notify(), 這樣的代碼,就能夠實現不同類之間的線程同步。
  
  本文并不強烈推薦這種用法,只是說明,有這樣一種方法存在。
  
  
  
  本文推薦第二種方法,(2)用參數傳遞的方法,把同步對象傳遞給不同的類。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 广水市| 连云港市| 天台县| 泽库县| 台东市| 平安县| 富裕县| 安仁县| 桦川县| 敦化市| 金门县| 基隆市| 无极县| 广灵县| 镇康县| 江源县| 虹口区| 衢州市| 兴和县| 晋宁县| 长岭县| 宁南县| 福清市| 桃园县| 赤壁市| 江西省| 九寨沟县| 独山县| 共和县| 蒙城县| 三原县| 米脂县| 永昌县| 瓮安县| 华池县| 辽中县| 榆林市| 林甸县| 衡东县| 乌恰县| 阿荣旗|