亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

再論Java Swing線程

2019-11-17 06:34:22
字體:
來源:轉載
供稿:網友

  不正確的Swing線程是運行緩慢、無響應和不穩定的Swing應用的主要原因之一。這是許多原因造成的,從開發人員對Swing單線程模型的誤解,到保證正確的線程執行的困難。即使對Swing線程進行了很多努力,應用線程邏輯也是很難理解和維護的。本文闡述了如何在開發Swing應用中使用事件驅動編程,以大大簡化開發、維護,并提供高靈活性。

  背景

  既然我們是要簡化Swing應用的線程,首先讓我們來看看Swing線程是怎么工作的,為什么它是必須的。Swing API是圍繞單線程模型設計的。這意味著Swing組件必須總是通過同一個線程來修改和操縱。為什么采用單線程模型,這有很多原因,包括開發成本和同步Swing的復雜性--這都會造成一個遲鈍的API。為了達到單線程模型,有一個專門的線程用于和Swing組件交互。這個線程就是大家熟知的Swing線程,AWT(有時也發音為“ought”)線程,或者事件分派線程。在本文的下面的部分,我選用Swing線程的叫法。
既然Swing線程是和Swing組件進行交互的唯一的線程,它就被賦予了很多責任。所有的繪制和圖形,鼠標事件,組件事件,按鈕事件,和所有其它事件都發生在Swing線程。因為Swing線程的工作已經非常沉重了,當太多其它工作在Swing線程中進行處理時就會發生問題。會引起這個問題的最常見的位置是在非Swing處理的地方,像發生在一個事件監聽器方法中,比如JButton的ActionListener,的數據庫查找。既然ActionListener的actionPerformed()方法自動在Swing線程中執行,那么,數據庫查找也將在Swing線程中執行。這將占用了Swing的工作,阻止它處理它的其它任務--像繪制,響應鼠標移動,處理按鈕事件,和應用的縮放。用戶以為應用死掉了,但實際上并不是這樣。在適當的線程中執行代碼對確保系統正常地執行非常重要。

  既然我們已經看到了在適當的線程中執行Swing應用的代碼是多么重要,現在讓我們如何實現這些線程。我們看看將代碼放入和移出Swing線程的標準機制。在講述過程中,我將突出幾個和標準機制有關的問題和難點。正如我們看到的,大部分的問題都來自于企圖在異步的Swing線程模型上實現同步的代碼模型。從那兒,我們將看到如何修改我們的例子到事件驅動--移植整個方式到異步模型。
  通用Swing線程解決方案

  讓我們以一個最常用的Swing線程錯誤開始。我們將企圖使用標準的技術來修正這個問題。在這個過程中,我們將看到實現正確的Swing線程的復雜性和常見困難。并且,注重在修正這個Swing線程問題中,許多中間的例子也是不能工作的。在例子中,我在代碼失敗的地方以//broken開頭標出。好了,現在,讓我們進入我們的例子吧。

  假設我們在執行圖書查找。我們有一個簡單的用戶界面,包括一個查找文本域,一個查找按鈕,和一個輸出的文本區域。這個接口如圖1所示。不要批評我的UI設計,這個確實很丑陋,我承認。

再論Java Swing線程(圖一)
圖 1. 基本查詢用戶界面

  用戶輸入書的標題,作者或者其它條件,然后顯示一個結果的列表。下面的代碼例子演示了按鈕的ActionListener在同一個線程中調用lookup()方法。在這些例子中,我使用了thread.sleep()休眠5秒來作為一個占位的外部查找。線程休眠的結果等同于一個耗時5秒的同步的服務器調用。

PRivate void searchButton_actionPerformed()
{
 outputTA.setText("Searching for: " + searchTF.getText());
 //Broken!! Too mUCh work in the Swing
 thread String[] results = lookup(searchTF.getText());
 outputTA.setText("");
 for (int i = 0; i < results.length; i++)
 {
  String result = results[i];
  outputTA.setText(outputTA.getText() + '/n' + result);
  }
}
  假如你運行這段代碼(完整的代碼可以在這兒下載),你會立即發現存在一些問題。圖2顯示了查找運行中的一個屏幕截圖。

再論Java Swing線程(圖二)
圖 2. 在Swing線程中進行查找

  注重Go按鈕看起來是被按下了。這是因為actionPerformed方法通知了按鈕繪制為非按下外觀,但是還沒有返回。你也會發現要查找的字串“abcde”并沒有出現在文本區域中。searchButton_actionPerformed的第1行代碼將文本區域設置為要查找的字串。但是,注重Swing重畫并不是立即執行的。而是把重畫請求放置到Swing事件隊列中等待Swing線程處理。但是這兒,我們因查找處理占用了Swing線程,所以,它還不能馬上進行重畫。

  要修正這些問題,讓我們把查找操作移入非Swing線程中。我們第一個想到的就是讓整個方法在一個新的線程中執行。這樣作的問題是Swing組件,本例中的文本區域,只能從Swing線程中進行編輯。下面是修改后的searchButton_actionPerformed方法:

private void searchButton_actionPerformed()
{
 outputTA.setText("Searching for: " + searchTF.getText());
 //the String[][] is used to allow access to
 // setting the results from an inner class
 final String[][] results = new String[1][1];
 new Thread()
 {
  public void run()
  {
   results[0] = lookup(searchTF.getText());
   }
  }.start();
 outputTA.setText("");
 for (int i = 0; i < results[0].length; i++)
  {
  String result = results[0][i];
  outputTA.setText(outputTA.getText() + '/n' + result);
  }
}
  這種方法有很多問題。注重final String[][] 。這是一個處理匿名內部類和作用域的不得已的替代?;旧?,在匿名內部類中使用的,但在外部環繞類作用域中定義的任何變量都需要定義為final。你可以通過創建一個數組來持有變量解決這個問題。這樣的話,你可以創建數組為final的,修改數組中的元素,而不是數組的引用自身。既然我們已經解決這個問題,讓我們進入真正的問題所在吧。圖3顯示了這段代碼運行時發生的情況:

再論Java Swing線程(圖三)
圖 3. 在Swing線程外部進行查找

  界面顯示了一個null,因為顯示代碼在查找代碼完成前被處理了。這是因為一旦新的線程啟動了,代碼塊繼續執行,而不是等待線程執行完畢。這是那些希奇的并發代碼塊中的一個,下面將把它編寫到一個方法中使其能夠真正執行。

  在SwingUtilities類中有兩個方法可以幫助我們解決這些問題:invokerLater()和invokeAndWait()。每一個方法都以一個Runnable作為參數,并在Swing線程中執行它。invokeAndWait()方法阻塞直到Runnnable執行完畢;invokeLater()異步地執行Runnable。invokeAndWait()一般不贊成使用,因為它可能導致嚴重的線程死鎖,對你的應用造成嚴重的破壞。所以,讓我們把它放置一邊,使用invokeLater()方法。
要修正最后一個變量變量scooping和執行順序的問題,我們必須將文本區域的getText()和setText()方法調用移入一個Runnable,只有在查詢結果返回后再執行它,并且在Swing線程中執行。我們可以這樣作,創建一個匿名Runnable傳遞給invokeLater(),包括在新線程的Runnable后的文本區域操作。這保證了Swing代碼不會在查找結束之前執行。下面是修正后的代碼:

private void searchButton_actionPerformed()
{
 outputTA.setText("Searching for: " + searchTF.getText());
 final String[][] results = new String[1][1];
 new Thread()
 {
  public void run()
  { //get results.
   results[0] = lookup(searchTF.getText())
   // send runnable to the Swing thread
   // the runnable is queued after the
   // results are returned
   SwingUtilities.invokeLater(
    new Runnable()
    {
     public void run()
     {
      // Now we're in the Swing thread
      outputTA.setText("");
      for (int i = 0; i < results[0].length; i++)
      {
       String result = results[0][i];
       outputTA.setText( outputTA.getText() + '/n' + result);
       }
      }
    }
   );
  }
 }.start();}
  這可以工作,但是這樣做令人非常頭痛。我們不得不對通過匿名線程執行的順序,我們還不得不處理困難的scooping問題。問題并不少見,并且,這只是一個非常簡單的例子,我們已經碰到了作用域,變量傳遞,和執行順序等一系列問題。相像一個更復雜的問題,包含了幾層嵌套,共享的引用和指定的執行順序。這種方法很快就失控了。



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩小视频在线观看| 97久久超碰福利国产精品…| 色777狠狠综合秋免鲁丝| 国产香蕉精品视频一区二区三区| 国产精品高清在线| 国产视频观看一区| 午夜精品久久17c| 日本高清不卡的在线| 不卡毛片在线看| 欧美一级大片在线观看| 日韩精品在线免费观看视频| 久久精品国产成人| 中文字幕av一区二区三区谷原希美| 色婷婷成人综合| 亚洲欧美国产日韩天堂区| 成人h视频在线| 欧美小视频在线| 欧美成人精品不卡视频在线观看| 欧美精品制服第一页| 日韩不卡中文字幕| 欧美精品一区二区免费| 久久男人资源视频| 91精品在线播放| 国产一区二区视频在线观看| 欧美日在线观看| 国产精品美女无圣光视频| 欧美xxxx18性欧美| 国产日韩精品在线播放| 美女999久久久精品视频| 国产精品精品视频一区二区三区| 国产成人亚洲综合| 亚洲精品美女在线观看播放| 亚洲free性xxxx护士白浆| 日韩av电影手机在线观看| 国产午夜精品视频免费不卡69堂| 欧美国产一区二区三区| 一区二区三区国产在线观看| 久久久久99精品久久久久| 亚洲免费一级电影| 日韩精品久久久久久福利| 亚洲精品小视频| 亚洲男人天堂网站| 热草久综合在线| 国产日韩精品在线观看| 久久亚洲精品小早川怜子66| 亚洲国产小视频| 国产精品高清网站| 亚洲二区在线播放视频| 青青a在线精品免费观看| 国产精品1234| 欧美激情亚洲自拍| 日韩久久精品电影| 国产精品免费一区二区三区都可以| 国产一区二区三区毛片| 成人国产在线视频| 亚洲色图狂野欧美| 亚洲一区二区在线播放| 成人激情视频免费在线| 麻豆乱码国产一区二区三区| 久久偷看各类女兵18女厕嘘嘘| 91精品国产成人| 不卡在线观看电视剧完整版| 国产精品久久久久免费a∨大胸| 91亚洲va在线va天堂va国| 精品久久久999| 综合网日日天干夜夜久久| 日韩精品一区二区三区第95| 久久久噜噜噜久久中文字免| 欧美自拍视频在线| 国产精品久久久一区| 高潮白浆女日韩av免费看| 亚洲伊人久久综合| 亚洲系列中文字幕| 色综合色综合久久综合频道88| 亚洲xxx视频| 不卡中文字幕av| 韩国三级日本三级少妇99| 久久99精品久久久久久琪琪| 97超碰蝌蚪网人人做人人爽| 日韩av一卡二卡| 欧美在线不卡区| 欧美日韩中文字幕综合视频| 国产精品免费视频xxxx| 久久久久久999| 久久影视电视剧免费网站清宫辞电视| 国产精品99久久久久久久久| 亚洲天堂av高清| 国内精品视频久久| 亚洲激情自拍图| 国产成人福利网站| 在线电影中文日韩| 国产日本欧美一区| 国产精品成人一区二区| 国产精品极品美女在线观看免费| 亚洲一区第一页| 久久精品电影网站| 欧美成人三级视频网站| 久久久久久亚洲| 亚洲高清色综合| 国产亚洲精品久久久久久777| 亚洲有声小说3d| 国产va免费精品高清在线| 国产精品久久久久久久久久新婚| 中文字幕久热精品在线视频| 久久久免费av| 91精品视频观看| 欧美日韩国产精品一区| 国产精品6699| 欧美一区二区三区图| 亚洲国产天堂久久综合| 欧洲美女7788成人免费视频| 一区二区三区久久精品| 亚洲欧美日韩在线高清直播| 国产精品亚洲一区二区三区| 日韩国产高清视频在线| 国产精品久久久久av免费| 亚洲视频欧美视频| 欧美激情国产高清| 欧美人与性动交a欧美精品| 欧美午夜久久久| 色yeye香蕉凹凸一区二区av| 亚洲成人黄色网址| 国产99久久精品一区二区永久免费| 日韩精品久久久久久福利| 日韩一区二区三区国产| 欧美日韩中文字幕| 另类图片亚洲另类| 97视频网站入口| 91精品国产网站| 欧美久久精品一级黑人c片| 欧美性xxxxhd| 国产成人在线一区| 国产人妖伪娘一区91| 国内精品一区二区三区| 国产亚洲精品激情久久| 国产精品一二三视频| 欧美成年人视频| 日韩有码片在线观看| 日本久久久久久久久| 91精品视频免费| 欧美成人精品在线观看| 亚洲欧洲在线看| 3344国产精品免费看| 日韩国产精品视频| 久久久日本电影| 久久久久九九九九| 午夜精品一区二区三区在线| 亚洲网站在线观看| 日韩av在线网址| 精品久久香蕉国产线看观看gif| 久久久精品美女| 日韩欧美国产成人| 97国产一区二区精品久久呦| 久久五月情影视| 成人性生交大片免费看小说| 成人黄色在线免费| 色综合影院在线| 久久久久九九九九| 亚洲最大av网| 精品国产一区二区三区四区在线观看| 国产ts人妖一区二区三区| 欧美日韩一区二区三区| 欧美有码在线观看| 欧美限制级电影在线观看|