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

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

死鎖

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

  由于線程可能進入堵塞狀態,而且由于對象可能擁有“同步”方法——除非同步鎖定被解除,否則線程不能訪問那個對象——所以一個線程完全可能等候另一個對象,而另一個對象又在等候下一個對象,以此類推。這個“等候”鏈最可怕的情形就是進入封閉狀態——最后那個對象等候的是第一個對象!此時,所有線程都會陷入無休止的相互等待狀態,大家都動彈不得。我們將這種情況稱為“死鎖”。盡管這種情況并非經常出現,但一旦碰到,程序的調試將變得異常艱難。
  就語言本身來說,尚未直接提供防止死鎖的幫助措施,需要我們通過謹慎的設計來避免。假如有誰需要調試一個死鎖的程序,他是沒有任何竅門可用的。
  1. java 1.2對stop(),suspend(),resume()以及destroy()的反對
  為減少出現死鎖的可能,Java 1.2作出的一項貢獻是“反對”使用Thread的stop(),suspend(),resume()以及destroy()方法。
  之所以反對使用stop(),是因為它不安全。它會解除由線程獲取的所有鎖定,而且假如對象處于一種不連貫狀態(“被破壞”),那么其他線程能在那種狀態下檢查和修改它們。結果便造成了一種微妙的局面,我們很難檢查出真正的問題所在。所以應盡量避免使用stop(),應該采用Blocking.java那樣的方法,用一個標志告訴線程什么時候通過退出自己的run()方法來中止自己的執行。
  假如一個線程被堵塞,比如在它等候輸入的時候,那么一般都不能象在Blocking.java中那樣輪詢一個標志。但在這些情況下,我們仍然不該使用stop(),而應換用由Thread提供的interrupt()方法,以便中止并退出堵塞的代碼。
  //: Interrupt.java
  // The alternative apPRoach to using stop()
  // when a thread is blocked
  import java.awt.*;
  import java.awt.event.*;
  import java.applet.*;
  class Blocked extends Thread {
   public synchronized void run() {
   try {
   wait(); // Blocks
   } catch(InterruptedException e) {
   System.out.println("InterruptedException");
   }
   System.out.println("Exiting run()");
   }
  }
  public class Interrupt extends Applet {
   private Button
   interrupt = new Button("Interrupt");
   private Blocked blocked = new Blocked();
   public void init() {
   add(interrupt);
  interrupt.addActionListener(
   new ActionListener() {
   public
   void actionPerformed(ActionEvent e) {
   System.out.println("Button pressed");
   if(blocked == null) return;
   Thread remove = blocked;
   blocked = null; // to release it
   remove.interrupt();
   }
   });
   blocked.start();
   }
   public static void main(String[] args) {
   Interrupt applet = new Interrupt();
   Frame aFrame = new Frame("Interrupt");
   aFrame.addWindowListener(
   new WindowAdapter() {
   public void windowClosing(WindowEvent e) {
   System.exit(0);
   }
   });
   aFrame.add(applet, BorderLayout.CENTER);
   aFrame.setSize(200,100);
   applet.init();
   applet.start();
   aFrame.setVisible(true);
   }
  } ///:~
  Blocked.run()內部的wait()會產生堵塞的線程。當我們按下按鈕以后,blocked(堵塞)的句柄就會設為null,使垃圾收集器能夠將其清除,然后調用對象的interrupt()方法。假如是首次按下按鈕,我們會看到線程正常退出。但在沒有可供“殺死”的線程以后,看到的便只是按鈕被按下而已。
  suspend()和resume()方法天生輕易發生死鎖。調用suspend()的時候,目標線程會停下來,但卻仍然持有在這之前獲得的鎖定。此時,其他任何線程都不能訪問鎖定的資源,除非被“掛起”的線程恢復運行。對任何線程來說,假如它們想恢復目標線程,同時又試圖使用任何一個鎖定的資源,就會造成令人難堪的死鎖。所以我們不應該使用suspend()和resume(),而應在自己的Thread類中置入一個標志,指出線程應該活動還是掛起。若標志指出線程應該掛起,便用wait()命其進入等待狀態。若標志指出線程應當恢復,則用一個notify()重新啟動線程。我們可以修改前面的Counter2.java來實際體驗一番。盡管兩個版本的效果是差不多的,但大家會注重到代碼的組織結構發生了很大的變化——為所有“聽眾”都使用了匿名的內部類,而且Thread是一個內部類。這使得程序的編寫稍微方便一些,因為它取消了Counter2.java中一些額外的記錄工作。
  //: Suspend.java
  // The alternative approach to using suspend()
  // and resume(), which have been deprecated
  // in Java 1.2.
  import java.awt.*;
  import java.awt.event.*;
  import java.applet.*;
  
  public class Suspend extends Applet {
   private TextField t = new TextField(10);
   private Button
   suspend = new Button("Suspend"),
   resume = new Button("Resume");
   class Suspendable extends Thread {
   private int count = 0;
   private boolean suspended = false;
   public Suspendable() { start(); }
   public void fauxSuspend() {
   suspended = true;
   }
   public synchronized void fauxResume() {
   suspended = false;
   notify();
   }
   public void run() {
   while (true) {
   try {
   sleep(100);
   synchronized(this) {
   while(suspended)
   wait();
   }
   } catch (InterruptedException e){}
   t.setText(Integer.toString(count++));
   }
   }
   }
   private Suspendable ss = new Suspendable();
   public void init() {
   add(t);
   suspend.addActionListener(
   new ActionListener() {
   public
   void actionPerformed(ActionEvent e) {
   ss.fauxSuspend();
   }
   });
   add(suspend);
   resume.addActionListener(
   new ActionListener() {
   public
   void actionPerformed(ActionEvent e) {
   ss.fauxResume();
   }
   });
   add(resume);
   }
   public static void main(String[] args) {
   Suspend applet = new Suspend();
   Frame aFrame = new Frame("Suspend");
   aFrame.addWindowListener(
   new WindowAdapter() {
   public void windowClosing(WindowEvent e){
   System.exit(0);
   }
   });
   aFrame.add(applet, BorderLayout.CENTER);
   aFrame.setSize(300,100);
   applet.init();
   applet.start();
   aFrame.setVisible(true);
   }
  }
  Suspendable中的suspended(已掛起)標志用于開關“掛起”或者“暫停”狀態。為掛起一個線程,只需調用fauxSuspend()將標志設為true(真)即可。對標志狀態的偵測是在run()內進行的。就象本章早些時候提到的那樣,wait()必須設為“同步”(synchronized),使其能夠使用對象鎖。在fauxResume()中,suspended標志被設為false(假),并調用notify()——由于這會在一個“同步”從句中喚醒wait(),所以fauxResume()方法也必須同步,使其能在調用notify()之前取得對象鎖(這樣一來,對象鎖可由要喚醍的那個wait()使用)。假如遵照本程序展示的樣式,可以避免使用wait()和notify()。
  Thread的destroy()方法根本沒有實現;它類似一個根本不能恢復的suspend(),所以會發生與suspend()一樣的死鎖問題。然而,這一方法沒有得到明確的“反對”,也許會在Java以后的版本(1.2版以后)實現,用于一些可以承受死鎖危險的非凡場合。
  大家可能會希奇當初為什么要實現這些現在又被“反對”的方法。之所以會出現這種情況,大概是由于Sun公司主要讓技術人員來決定對語言的改動,而不是那些市場銷售人員。通常,技術人員比搞銷售的更能理解語言的實質。當初犯下了錯誤以后,也能較為理智地正視它們。這意味著Java能夠繼續進步,即便這使Java程序員多少感到有些不便。就我自己來說,寧愿面對這些不便之處,也不愿看到語言停滯不前。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 欧美日韩手机在线观看 | 国产精品资源手机在线播放 | 一级做a爰性色毛片免费1 | 欧美雌雄另类xxxxx | 一级黄色毛片免费 | 久久国产精品久久久久 | 一级免费特黄视频 | 国产日韩中文字幕 | 一区二区三区日韩电影 | 深夜福利久久久 | 黄色大片在线观看 | wwwxxx免费视频| 成人免费观看av | 国产午夜精品理论片a级探花 | 黄色免费高清网站 | va视频在线 | 欧美五月婷婷 | 粉嫩蜜桃麻豆免费大片 | 色妹子久久 | 沉沦的校花奴性郑依婷c到失禁 | 外国一级黄色片 | 免费小毛片 | 2019中文字幕在线播放 | 欧美成年人视频 | 黄色网址进入 | 日韩在线激情 | 欧洲伊人网| 欧洲精品久久 | 国产精品免费一区二区 | 亚洲精品午夜电影 | 亚洲一区二区三区高清视频 | 久久久久久免费免费 | 男男啪羞羞视频网站 | 久久福利国产 | 久久精品中文字幕一区 | 国产精品欧美久久久久一区二区 | 91成人影库| 中文日产幕无线码6区免费版 | 亚洲91网 | 久久国产乱子伦精品 | 久久国产免费 |