熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

Java 線程缺陷和副作用的解決辦法(1)

2013-11-23 19:59:17  來源: Java高級技術 

  synchronize(同步)

  讓我們回憶一下上篇文章中講的線程允許兩個或者更多個進程同時執行實際上這些線程也可以共享對象和數據在這種情形下你要知道不同的線程在同一時間內不能存取同一數據因為一開始設計Java的時候就采用了線程的概念Java語言定義了一個特殊的關鍵字synchronize(同步)該關鍵字可以應用到代碼塊上代碼塊也包括入口方法該關鍵字的目的是防止多個線程在同一時間執行同一代碼塊內的代碼

  定義一個同步的方法格式如下

  [public|private] synchronized {type}
  methodname()
  一個把同步這個關鍵字應用到方法中的簡單的例子

  public class someClass
  {
   public void aMethod()
   {
    // Some code
    synchronized(this)
    {
     // Synchronized code block
    }
    // more code
   }
  }

  同步化的關鍵字可以保證在同一時間內只有一個線程可以執行該代碼段而任何其他要用到該段代碼的線程將被阻塞直到第一個線程執行完該段代碼

  死鎖和饑餓

  對於饑餓的定義由於別的並發的激活的過程持久占有所需資源是莫個異步過程載客預測的時間內不能被激活

  最常遇到的線程的兩個缺陷是死鎖和饑餓當一個或者多個進程在一個給定的任務中協同作用互相干涉而導致一個或者更多進程永遠等待下去死鎖就發生了與此類似它當一個進程永久性地占有資源使得其他進程得不到該資源就發生了饑餓

  首先我們看一下死鎖問題考慮一個簡單的例子假如你到ATM機上取錢但是你卻看到如下的信息現在有沒有現金請等會兒再試你需要錢所以你就等了一會兒再試但是你又看到同樣的信息與此同時在你後面一輛運款裝甲車正等待著把錢放進ATM中但是運款裝甲車到不了ATM取款機因為你的汽車擋著道而你又要取到錢才會離開原地這種情況下就發生了死鎖

  在饑餓的情形下系統不處於死鎖狀態中因為有一個進程仍在處理之中只是其他進程永遠得不到執行的機會在什麼樣的環境下會導致饑餓的發生沒有預先確定好的規則而一旦發生下面四種情況之一就會導致死鎖的發生

  相互排斥: 一個線程或者進程永遠占有一共享資源例如獨占該資源

  循環等待: 進程A等待進程B而後者又在等待進程C而進程C又在等待進程A

  部分分配: 資源被部分分配例如進程A和B都需要用訪問一個文件並且都要用到打印機進程A獲得了文件資源進程B獲得了打印機資源但是兩個進程不能獲得全部的資源

  缺少優先權: 一個進程訪問了某個資源但是一直不釋放該資源即使該進程處於阻塞狀態

  如果上面四種情形都不出現系統就不會發生死鎖請再看一下剛才的文件/打印機的例子當其中一個進程判斷出它得不到它所需要的第二個資源就釋放已經得到的第一個資源那麼第二個教程可以獲得兩個資源並能夠運行下去

  線程的高級用法

  到目前為止我們已經談到創建和管理線程的基本知識你需要做的就是啟動一個線程並讓它運行你的應用程序也許希望等待一個線程執行完畢也許打算發送一個信息給線程或者只打算讓線程在處理之前休眠一會兒線程類提供了四種對線程進行操作的API調用

  Join

  如果一個應用程序需要執行很多時間比如一個耗時很長的計算工作你可以把該計算工作設計成線程但是假定還有另外一個線程需要計算結果當計算結果出來後如何讓那個線程知道計算結果呢?解決該問題的一個方法是讓第二個線程一直不停地檢查一些變量的狀態直到這些變量的狀態發生改變這樣的方式在UNIX風格的服務器中常常用到Java提供了一個更加簡單的機制即線程類中的join 方法

  join 方法使得一個線程等待另外一個線程的結束例如一個GUI (或者其他線程)使用join方法等待一個子線程執行完畢

  CompleteCalcThread t = new
  CompleteCalcThread();
  tstart();
  //
  // 做一會兒其他的事情
  // 然後等待
  tjoin();
  // 使用計算結果

  你可以看到用對子線程使用join方法等待子線程執行完畢 Join 有三種格式

  void join(): 等待線程執行完畢
  void join(long timeout): 最多等待某段時間讓線程完成
  void join(long milliseconds int nanoseconds): 最多等待某段時間(毫秒+納秒)讓線程完成

  線程API isAlive同join相關聯時是很有用的一個線程在start(此時run方法已經啟動)之後在stop之前的某時刻處於isAlive 狀態

  對於編寫線程的程序員來說還有其他兩個有用的線程API即wait和 notify使用這兩個API我們可以精確地控制線程的執行過程考慮一個簡單的例子有個生產者線程和消費者線程為了讓應用程序更有效率所以我們不打算采用查詢等待的方法當消費者可以消費對象時消費者需要得知該信息

  我們可以把該例子闡述如下生產者線程不斷地在運行著把項目放入列表中該列表的add方法由synchronize 關鍵字保護著當一個對象添加到列表中生產者就可以通知消費者它已經添加一個對象消費者可以消費該對象了


From:http://tw.wingwit.com/Article/program/Java/gj/201311/27776.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.