麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

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

為何會堵塞

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. 暫停和恢復
  這個例子接下來的一部分引入了“掛起”或者“暫停”(Suspend)的概述。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的一部分,不象

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 91网站链接 | 99热草| 日本不卡视频在线观看 | 免费国产之a视频 | 黑人一区二区 | 黄网站免费在线看 | 一本色道久久综合狠狠躁篇适合什么人看 | 全黄毛片| 九九黄色 | 色人阁在线视频 | 一级一级一级毛片 | 久久不射电影网 | 欧美成人免费电影 | 天天看天天摸天天操 | 一本到免费视频 | 日日噜噜噜夜夜狠狠久久蜜桃 | 亚洲精中文字幕二区三区 | 国产一区精品在线观看 | 久久久久久久久国产 | 国产成人精品视频在线 | 电影av在线 | 男人的天堂视频网站 | 精品一区二区三区中文字幕老牛 | 成人综合一区二区 | 国产精品久久久久久久久久久久久久久久 | 看一级毛片 | 在线91观看| 午夜精品福利视频 | 高清国产福利 | 亚洲最大久久 | 日韩视频在线不卡 | av在线等| 中文字幕国产欧美 | 久久精品视频首页 | 日本在线观看中文字幕 | 国产精品啪| 538任你躁在线精品视频网站 | 亚洲成人中文字幕在线 | 久久久久久三区 | 国产99精品在线 | 免费在线看a |