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

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

為何會堵塞

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

  堵塞狀態是前述四種狀態中最有趣的,值得我們作進一步的探討。線程被堵塞可能是由下述五方面的原因造成的:
  (1) 調用sleep(毫秒數),使線程進入“睡眠”狀態。在規定的時間內,這個線程是不會運行的。
  (2) 用suspend()暫停了線程的執行。除非線程收到resume()消息,否則不會返回“可運行”狀態。
  (3) 用wait()暫停了線程的執行。除非線程收到nofify()或者notifyAll()消息,否則不會變成“可運行”(是的,這看起來同原因2非常相象,但有一個明顯的區別是我們馬上要揭示的)。
  (4) 線程正在等候一些IO(輸入輸出)操作完成。
  (5) 線程試圖調用另一個對象的“同步”方法,但那個對象處于鎖定狀態,暫時無法使用。
  亦可調用yield()(Thread類的一個方法)自動放棄CPU,以便其他線程能夠運行。然而,假如調度機制覺得我們的線程已擁有足夠的時間,并跳轉到另一個線程,就會發生同樣的事情。也就是說,沒有什么能防止調度機制重新啟動我們的線程。線程被堵塞后,便有一些原因造成它不能繼續運行。
  下面這個例子展示了進入堵塞狀態的全部五種途徑。它們全都存在于名為Blocking.java的一個文件中,但在這兒采用散落的片斷進行解釋(大家可注重到片斷前后的“Continued”以及“Continuing”標志。利用第17章介紹的工具,可將這些片斷連結到一起)。首先讓我們看看基本的框架:
  //: Blocking.java
  // Demonstrates the various ways a thread
  // can be blocked.
  import java.awt.*;
  import java.awt.event.*;
  import java.applet.*;
  import java.io.*;
  //////////// The basic framework ///////////
  class Blockable extends Thread {
   PRivate Peeker peeker;
   protected TextField state = new TextField(40);
   protected int i;
   public Blockable(Container c) {
   c.add(state);
   peeker = new Peeker(this, c);
   }
   public synchronized int read() { return i; }
   protected synchronized void update() {
   state.setText(getClass().getName()
   + " state: i = " + i);
   }
   public void stopPeeker() {
   // peeker.stop(); Deprecated in Java 1.2
   peeker.terminate(); // The preferred approach
   }
  }
  class Peeker extends Thread {
   private Blockable b;
   private int session;
   private TextField status = new TextField(40);
   private boolean stop = false;
   public Peeker(Blockable b, Container c) {
   c.add(status);
   this.b = b;
   start();
   }
   public void terminate() { stop = true; }
   public void run() {
   while (!stop) {
   status.setText(b.getClass().getName()
   + " Peeker " + (++session)
   + "; value = " + b.read());
   try {
   sleep(100);
   } catch (InterruptedException e){}
   }
   }
  } ///:Continued
  Blockable類打算成為本例所有類的一個基礎類。一個Blockable對象包含了一個名為state的TextField(文本字段),用于顯示出對象有關的信息。用于顯示這些信息的方法叫作update()。我們發現它用getClass.getName()來產生類名,而不是僅僅把它打印出來;這是由于update(0不知道自己為其調用的那個類的準確名字,因為那個類是從Blockable衍生出來的。
  在Blockable中,變動指示符是一個int i;衍生類的run()方法會為其增值。
  針對每個Bloackable對象,都會啟動Peeker類的一個線程。Peeker的任務是調用read()方法,檢查與自己關聯的Blockable對象,看看i是否發生了變化,最后用它的status文本字段報告檢查結果。注重read()和update()都是同步的,要求對象的鎖定能自由解除,這一點非常重要。
  1. 睡眠
  這個程序的第一項測試是用sleep()作出的:
  ///:Continuing
  ///////////// Blocking via sleep() ///////////
  class Sleeper1 extends Blockable {
   public Sleeper1(Container c) { super(c); }
   public synchronized void run() {
   while(true) {
   i++;
   update();
   try {
   sleep(1000);
   } catch (InterruptedException e){}
   }
   }
  }
  class Sleeper2 extends Blockable {
   public Sleeper2(Container c) { super(c); }
   public void run() {
   while(true) {
   change();
   try {
   sleep(1000);
   } catch (InterruptedException e){}
   }
   }
   public synchronized void change() {
   i++;
   update();
   }
  } ///:Continued
  在Sleeper1中,整個run()方法都是同步的。我們可看到與這個對象關聯在一起的Peeker可以正常運行,直到我們啟動線程為止,隨后Peeker便會完全停止。這正是“堵塞”的一種形式:因為Sleeper1.run()是同步的,而且一旦線程啟動,它就肯定在run()內部,方法永遠不會放棄對象鎖定,造成Peeker線程的堵塞。
  Sleeper2通過設置不同步的運行,提供了一種解決方案。只有change()方法才是同步的,所以盡管run()位于sleep()內部,Peeker仍然能訪問自己需要的同步方法——read()。在這里,我們可看到在啟動了Sleeper2線程以后,Peeker會持續運行下去。
  2. 暫停和恢復
  這個例子接下來的一部分引入了“掛起”或者“暫?!保⊿uspend)的概述。Thread類提供了一個名為suspend()的方法,可臨時中止線程;以及一個名為resume()的方法,用于從暫停處開始恢復線程的執行。顯然,我們可以推斷出resume()是由暫停線程外部的某個線程調用的。在這種情況下,需要用到一個名為Resumer(恢復器)的獨立類。演示暫停/恢復過程的每個類都有一個相關的恢復器。如下所示:
  ///:Continuing
  /////////// Blocking via suspend() ///////////
  class SuspendResume extends Blockable {
   public SuspendResume(Container c) {
   super(c);
   new Resumer(this);
   }
  }
  class SuspendResume1 extends SuspendResume {
   public SuspendResume1(Container c) { super(c);}
   public synchronized void run() {
   while(true) {
   i++;
   update();
   suspend(); // Deprecated in Java 1.2
   }
   }
  }
  class SuspendResume2 extends SuspendResume {
   public SuspendResume2(Container c) { super(c);}
   public void run() {
   while(true) {
   change();
   suspend(); // Deprecated in Java 1.2
   }
   }
   public synchronized void change() {
   i++;
   update();
   }
  }
  class Resumer extends Thread {
   private SuspendResume sr;
   public Resumer(SuspendResume sr) {
   this.sr = sr;
   start();
   }
   public void run() {
   while(true) {
   try {
   sleep(1000);
   } catch (InterruptedException e){}
   sr.resume(); // Deprecated in Java 1.2
   }
   }
  } ///:Continued
  SuspendResume1也提供了一個同步的run()方法。同樣地,當我們啟動這個線程以后,就會發現與它關聯的Peeker進入“堵塞”狀態,等候對象鎖被釋放,但那永遠不會發生。和往常一樣,這個問題在SuspendResume2里得到了解決,它并不同步整個run()方法,而是采用了一個單獨的同步change()方法。
  對于Java 1.2,大家應注重suspend()和resume()已獲得強烈反對,因為suspend()包含了對象鎖,所以極易出現“死鎖”現象。換言之,很輕易就會看到許多被鎖住的對象在傻乎乎地等待對方。這會造成整個應用程序的“凝固”。盡管在一些老程序中還能看到它們的蹤跡,但在你寫自己的程序時,無論如何都應避免。本章稍后就會講述正確的方案是什么。
  3. 等待和通知
  通過前兩個例子的實踐,我們知道無論sleep()還是suspend()都不會在自己被調用的時候解除鎖定。需要用到對象鎖時,請務必注重這個問題。在另一方面,wait()方法在被調用時卻會解除鎖定,這意味著可在執行wait()期間調用線程對象中的其他同步方法。但在接著的兩個類中,我們看到run()方法都是“同步”的。在wait()期間,Peeker仍然擁有對同步方法的完全訪問權限。這是由于wait()在掛起內部調用的方法時,會解除對象的鎖定。
  我們也可以看到wait()的兩種形式。第一種形式采用一個以毫秒為單位的參數,它具有與sleep()中相同的含義:暫停這一段規定時間。區別在于在wait()中,對象鎖已被解除,而且能夠自由地退出wait(),因為一個notify()可強行使時間流逝。
  第二種形式不采用任何參數,這意味著wait()會持續執行,直到notify()介入為止。而且在一段時間以后,不會自行中止。
  wait()和notify()比較非凡的一個地方是這兩個方法都屬于基礎類Object的一部分,不象

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 峨边| 五家渠市| 小金县| 浑源县| 买车| 庐江县| 承德县| 禹城市| 合江县| 西畴县| 泾源县| 达拉特旗| 青龙| 吉木萨尔县| 克什克腾旗| 湘阴县| 苏州市| 本溪| 黄冈市| 阿尔山市| 长顺县| 潜山县| 民乐县| 海阳市| 迁西县| 吉安县| 九寨沟县| 黄浦区| 花莲县| 普兰店市| 宁乡县| 南充市| 临江市| 曲沃县| 马鞍山市| 普宁市| 汶上县| 启东市| 轮台县| 邛崃市| 武夷山市|