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

首頁(yè) > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

共享有限的資源

2019-11-18 13:23:01
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

  共享有限的資源
  可將單線程程序想象成一種孤立的實(shí)體,它能遍歷我們的問(wèn)題空間,而且一次只能做一件事情。由于只有一個(gè)實(shí)體,所以永遠(yuǎn)不必?fù)?dān)心會(huì)有兩個(gè)實(shí)體同時(shí)試圖使用相同的資源,就象兩個(gè)人同時(shí)都想停到一個(gè)車位,同時(shí)都想通過(guò)一扇門,甚至同時(shí)發(fā)話。
  進(jìn)入多線程環(huán)境后,它們則再也不是孤立的。可能會(huì)有兩個(gè)甚至更多的線程試圖同時(shí)同一個(gè)有限的資源。必須對(duì)這種潛在資源沖突進(jìn)行預(yù)防,否則就可能發(fā)生兩個(gè)線程同時(shí)訪問(wèn)一個(gè)銀行帳號(hào),打印到同一臺(tái)計(jì)算機(jī),以及對(duì)同一個(gè)值進(jìn)行調(diào)整等等。
  1 資源訪問(wèn)的錯(cuò)誤方法
  現(xiàn)在考慮換成另一種方式來(lái)使用本章頻繁見到的計(jì)數(shù)器。在下面的例子中,每個(gè)線程都包含了兩個(gè)計(jì)數(shù)器,它們?cè)趓un()里增值以及顯示。除此以外,我們使用了Watcher類的另一個(gè)線程。它的作用是監(jiān)視計(jì)數(shù)器,檢查它們是否保持相等。這表面是一項(xiàng)無(wú)意義的行動(dòng),因?yàn)榧偃绮榭创a,就會(huì)發(fā)現(xiàn)計(jì)數(shù)器肯定是相同的。但實(shí)際情況卻不一定如此。下面是程序的第一個(gè)版本:
  //: Sharing1.java
  // PRoblems with resource sharing while threading
  import java.awt.*;
  import java.awt.event.*;
  import java.applet.*;
  class TwoCounter extends Thread {
   private boolean started = false;
   private TextField
    t1 = new TextField(5),
    t2 = new TextField(5);
   private Label l =
    new Label("count1 == count2");
   private int count1 = 0, count2 = 0;
   // Add the display components as a panel
   // to the given container:
   public TwoCounter(Container c) {
    Panel p = new Panel();
    p.add(t1);
    p.add(t2);
    p.add(l);
    c.add(p);
   }
   public void start() {
    if(!started) {
     started = true;
     super.start();
    }
   }
   public void run() {
    while (true) {
     t1.setText(Integer.toString(count1++));
     t2.setText(Integer.toString(count2++));
     try {
      sleep(500);
     } catch (InterruptedException e){}
    }
   }
   public void synchTest() {
    Sharing1.incrementaccess();
    if(count1 != count2)
     l.setText("Unsynched");
   }
  }
  class Watcher extends Thread {
   private Sharing1 p;
   public Watcher(Sharing1 p) {
    this.p = p;
    start();
   }
   public void run() {
    while(true) {
     for(int i = 0; i < p.s.length; i++)
      p.s[i].synchTest();
     try {
      sleep(500);
     } catch (InterruptedException e){}
    }
   }
  }
  public class Sharing1 extends Applet {
   TwoCounter[] s;
   private static int accessCount = 0;
   private static TextField aCount =
    new TextField("0", 10);
   public static void incrementAccess() {
    accessCount++;
    aCount.setText(Integer.toString(accessCount));
   }
   private Button
    start = new Button("Start"),
    observer = new Button("Observe");
   private boolean isApplet = true;
   private int numCounters = 0;
   private int numObservers = 0;
   public void init() {
    if(isApplet) {
     numCounters =
      Integer.parseInt(getParameter("size"));
     numObservers =
      Integer.parseInt(
       getParameter("observers"));
    }
    s = new TwoCounter[numCounters];
    for(int i = 0; i < s.length; i++)
     s[i] = new TwoCounter(this);
    Panel p = new Panel();
    start.addActionListener(new StartL());
    p.add(start);
    observer.addActionListener(new ObserverL());
    p.add(observer);
    p.add(new Label("Access Count"));
    p.add(aCount);
    add(p);
   }
   class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
     for(int i = 0; i < s.length; i++)
      s[i].start();
    }
   }
   class ObserverL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
     for(int i = 0; i < numObservers; i++)
      new Watcher(Sharing1.this);
    }
   }
   public static void main(String[] args) {
    Sharing1 applet = new Sharing1();
    // This isn't an applet, so set the flag and
    // prodUCe the parameter values from args:
    applet.isApplet = false;
    applet.numCounters =
     (args.length == 0 ? 5 :
      Integer.parseInt(args[0]));
    applet.numObservers =
     (args.length < 2 ? 5 :
      Integer.parseInt(args[1]));
    Frame aFrame = new Frame("Sharing1");
    aFrame.addWindowListener(
     new WindowAdapter() {
      public void windowClosing(WindowEvent e){
       System.exit(0);
      }
     });
    aFrame.add(applet, BorderLayout.CENTER);
    aFrame.setSize(350, applet.numCounters *100);
    applet.init();
    applet.start();
    aFrame.setVisible(true);
   }
  }
  和往常一樣,每個(gè)計(jì)數(shù)器都包含了自己的顯示組件:兩個(gè)文本字段以及一個(gè)標(biāo)簽。根據(jù)它們的初始值,可知道計(jì)數(shù)是相同的。這些組件在TwoCounter構(gòu)建器加入Container。由于這個(gè)線程是通過(guò)用戶的一個(gè)“按下按鈕”操作啟動(dòng)的,所以start()可能被多次調(diào)用。但對(duì)一個(gè)線程來(lái)說(shuō),對(duì)Thread.start()的多次調(diào)用是非法的(會(huì)產(chǎn)生違例)。在started標(biāo)記和過(guò)載的start()方法中,大家可看到針對(duì)這一情況采取的防范措施。
  在run()中,count1和count2的增值與顯示方式表面上似乎能保持它們完全一致。隨后會(huì)調(diào)用sleep();若沒(méi)有這個(gè)調(diào)用,程序便會(huì)出錯(cuò),因?yàn)槟菚?huì)造成CPU難于交換任務(wù)。
  synchTest()方法采取的似乎是沒(méi)有意義的行動(dòng),它檢查count1是否等于count2;假如不等,就把標(biāo)簽設(shè)為“Unsynched”(不同步)。但是首先,它調(diào)用的是類Sharing1的一個(gè)靜態(tài)成員,以便增值和顯示一個(gè)訪問(wèn)計(jì)數(shù)器,指出這種檢查已成功進(jìn)行了多少次(這樣做的理由會(huì)在本例的其他版本中變得非常明顯)。
  Watcher類是一個(gè)線程,它的作用是為處于活動(dòng)狀態(tài)的所有TwoCounter對(duì)象都調(diào)用synchTest()。其間,它會(huì)對(duì)Sharing1對(duì)象中容納的數(shù)組進(jìn)行遍歷。可將Watcher想象成它擦過(guò)TwoCounter對(duì)象的肩膀不斷地“偷看”。
  Sharing1包含了TwoCounter對(duì)象的一個(gè)數(shù)組,它通過(guò)init()進(jìn)行初始化,并在我們按下“start”按鈕后作為線程啟動(dòng)。以后若按下“Observe”(觀察)按鈕,就會(huì)創(chuàng)建一個(gè)或者多個(gè)觀察器,并對(duì)毫不設(shè)防的TwoCounter進(jìn)行調(diào)查。
  注重為了讓它作為一個(gè)程序片在瀏覽器中運(yùn)行,Web頁(yè)需要包含下面這幾行:
  <applet code=Sharing1 width=650 height=500>

  <param name=size value="20">

  <param name=observers value="1">

  </applet>
  可自行改變寬度、高度以及參數(shù),根據(jù)自己的意愿進(jìn)行試驗(yàn)。若改變了size和observers,程序的行為也會(huì)發(fā)生變化。我們也注重到,通過(guò)從命令行接受參數(shù)(或者使用默認(rèn)值),它被設(shè)計(jì)成作為一個(gè)獨(dú)立的應(yīng)用程序運(yùn)行。
  下面才是最讓人“不可思議”的。在TwoCounter.run()中,無(wú)限循環(huán)只是不斷地重復(fù)相鄰的行:
  t1.setText(Integer.toString(count1++));
  t2.setText(Integer.toString(count2++));
  (和“睡眠”一樣,不過(guò)在這里并不重要)。但在程序運(yùn)行的時(shí)候,你會(huì)發(fā)現(xiàn)count1和count2被“觀察”(用Watcher觀察)的次數(shù)是不相等的!這是由線程的本質(zhì)造成的——它們可在任何時(shí)候掛起(暫停)。所以在上述兩行的執(zhí)行時(shí)刻之間,有時(shí)會(huì)出現(xiàn)執(zhí)行暫停現(xiàn)象。同時(shí),Watcher線程也正好跟隨著進(jìn)來(lái),并正好在這個(gè)時(shí)候進(jìn)行比較,造成計(jì)數(shù)器出現(xiàn)不相等的情況。
  本例揭示了使用線程時(shí)一個(gè)非常基本的問(wèn)題。我們跟無(wú)從知道一個(gè)線程什么時(shí)候運(yùn)行。想象自己坐在一張桌子前面,桌上放有一把叉子,預(yù)備叉起自己的最后一塊食物。當(dāng)叉子要碰到食物時(shí),食物卻忽然消失了(因?yàn)檫@個(gè)線程已被掛起,同時(shí)另一個(gè)線程進(jìn)來(lái)“偷”走了食物)。這便是我們要解決的問(wèn)題。
  有的時(shí)候,我們并不介意一個(gè)資源在嘗試使用它的時(shí)候是否正被訪問(wèn)(食物在另一些盤子里)。但為了讓多線程機(jī)制能夠正常運(yùn)轉(zhuǎn),需要采取一些措施來(lái)防止兩個(gè)線程訪問(wèn)相同的資源——至少在要害的時(shí)期。
  為防止出現(xiàn)這樣的沖突,只需在線程使用一個(gè)資源時(shí)為其加鎖即可。訪問(wèn)資源的第一個(gè)線程會(huì)其加上鎖以后,其他線程便

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 热@国产 | 草草视频免费观看 | 午夜视频亚洲 | 国内精品久久久久久久久久久久 | 成人wxx视频免费 | 国产精品视频yy9299一区 | 亚洲一区国产二区 | 色综合久久久久久久久久久 | 视频一区二区三区视频 | 中文字幕涩涩久久乱小说 | 国产精品99久久久久久大便 | 天天色宗合 | 4p嗯啊巨肉寝室调教男男视频 | 欧美a视频在线观看 | 最新se94se在线欧美 | 免费99热在线观看 | 免费观看一区二区三区视频 | 欧洲成人综合网 | 午夜精品影院 | 亚洲人成网站免费播放 | 日本a在线观看 | 爽妇网国产精品 | 日本看片一区二区三区高清 | 国产精品久久久久久久娇妻 | 手机在线看片国产 | 久久999精品久久久 国产噜噜噜噜久久久久久久久 | 欧美日韩一区,二区,三区,久久精品 | 中国a毛片 | 99国产精品欲a | 国产麻豆交换夫妇 | 青久草视频 | 国产成年人网站 | 色视频在线 | 久久丝袜脚交足黄网站免费 | 欧美一级免费视频 | 男女污视频在线观看 | 欧美精品在线视频观看 | 久久影院免费观看 | 国产一级毛片高清视频完整版 | 红杏亚洲影院一区二区三区 | 精品国产一区二区三区四区阿崩 |