<address id="xpjh9"><listing id="xpjh9"><meter id="xpjh9"></meter></listing></address>

<address id="xpjh9"><address id="xpjh9"><listing id="xpjh9"></listing></address></address>
<noframes id="xpjh9">
<noframes id="xpjh9">

<address id="xpjh9"><address id="xpjh9"><listing id="xpjh9"></listing></address></address>
    <form id="xpjh9"></form><address id="xpjh9"><listing id="xpjh9"><menuitem id="xpjh9"></menuitem></listing></address>

      <noframes id="xpjh9">
      VB.net 2010 視頻教程 VB.net 2010 視頻教程 VB.net 2010 視頻教程
      SQL Server 2008 視頻教程 c#入門經典教程 Visual Basic從門到精通視頻教程
      當前位置:
      首頁 > 編程開發 > Java教程 >
      • java教程之關于 java.util.concurrent 您不知道的 5 件事

      • 2015-01-24 09:41 來源:未知

      關于 java.util.concurrent 您不知道的 5 (相關java教程)件事,第 2 部分

      并發 Collections 提供了線程安全、經過良好調優的數據結構,簡化了并發編程。然而,在一些情形下,開發人員需要更進一步,思考如何調節和/或限制線程執行。由于 java.util.concurrent 的總體目標是簡化多線程編程,您可能希望該包包含同步實用程序,而它確實包含。
      本文是 第 1 部分 的延續,將介紹幾個比核心語言原語(監視器)更高級的同步結構,但它們還未包含在 Collection 類中。一旦您了解了這些鎖和門的用途,使用它們將非常直觀。

      1、  Semaphore

      在一些企業系統中,開發人員經常需要限制未處理的特定資源請求(線程/操作)數量,事實上,限制有時候能夠提高系統的吞吐量,因為它們減少了對特定資源的爭用。盡管完全可以手動編寫限制代碼,但使用 Semaphore 類可以更輕松地完成此任務,它將幫您執行限制,如清單 1 所示:
      清單 1. 使用 Semaphore 執行限制


      import java.util.*;import java.util.concurrent.*;
       
      public class SemApp
      {
          public static void main(String[] args)
          {
              Runnable limitedCall = new Runnable() {
                  final Random rand = new Random();
                  final Semaphore available = new Semaphore(3);
                  int count = 0;
                  public void run()
                  {
                      int time = rand.nextInt(15);
                      int num = count++;
                      
                      try
                      {
                          available.acquire();
                          
                          System.out.println("Executing " + 
                              "long-running action for " + 
                              time + " seconds... #" + num);
                      
                          Thread.sleep(time * 1000);
       
                          System.out.println("Done with #" + 
                              num + "!");
       
                          available.release();
                      }
                      catch (InterruptedException intEx)
                      {
                          intEx.printStackTrace();
                      }
                  }
              };
              
              for (int i=0; i<10; i++)
                  new Thread(limitedCall).start();
          }
      }
      即使本例中的 10 個線程都在運行(您可以對運行 SemApp 的 Java 進程執行 jstack 來驗證),但只有 3 個線程是活躍的。在一個信號計數器釋放之前,其他 7 個線程都處于空閑狀態。(實際上,Semaphore 類支持一次獲取和釋放多個 permit,但這不適用于本場景。)

      2、  CountDownLatch

      如果 Semaphore 是允許一次進入一個(這可能會勾起一些流行夜總會的保安的記憶)線程的并發性類,那么 CountDownLatch 就像是賽馬場的起跑門柵。此類持有所有空閑線程,直到滿足特定條件,這時它將會一次釋放所有這些線程。
      清單 2. CountDownLatch:讓我們去賽馬吧!


      import java.util.*;
      import java.util.concurrent.*;
       
      class Race
      {
          private Random rand = new Random();
          
          private int distance = rand.nextInt(250);
          private CountDownLatch start;
          private CountDownLatch finish;
          
          private List<String> horses = new ArrayList<String>();
          
          public Race(String... names)
          {
              this.horses.addAll(Arrays.asList(names));
          }
          
          public void run()
              throws InterruptedException
          {
              System.out.println("And the horses are stepping up to the gate...");
              final CountDownLatch start = new CountDownLatch(1);
              final CountDownLatch finish = new CountDownLatch(horses.size());
              final List<String> places = 
                  Collections.synchronizedList(new ArrayList<String>());
              
              for (final String h : horses)
              {
                  new Thread(new Runnable() {
                      public void run() {
                          try
                          {
                              System.out.println(h + 
                                  " stepping up to the gate...");
                              start.await();
                              
                              int traveled = 0;
                              while (traveled < distance)
                              {
                                  // In a 0-2 second period of time....
                                  Thread.sleep(rand.nextInt(3) * 1000);
                                  
                                  // ... a horse travels 0-14 lengths
                                  traveled += rand.nextInt(15);
                                  System.out.println(h + 
                                      " advanced to " + traveled + "!");
                              }
                              finish.countDown();
                              System.out.println(h + 
                                  " crossed the finish!");
                              places.add(h);
                          }
                          catch (InterruptedException intEx)
                          {
                              System.out.println("ABORTING RACE!!!");
                              intEx.printStackTrace();
                          }
                      }
                  }).start();
              }
       
              System.out.println("And... they're off!");
              start.countDown();        
       
              finish.await();
              System.out.println("And we have our winners!");
              System.out.println(places.get(0) + " took the gold...");
              System.out.println(places.get(1) + " got the silver...");
              System.out.println("and " + places.get(2) + " took home the bronze.");
          }
      }
       
      public class CDLApp
      {
          public static void main(String[] args)
              throws InterruptedException, java.io.IOException
          {
              System.out.println("Prepping...");
              
              Race r = new Race(
                  "Beverly Takes a Bath",
                  "RockerHorse",
                  "Phineas",
                  "Ferb",
                  "Tin Cup",
                  "I'm Faster Than a Monkey",
                  "Glue Factory Reject"
                  );
              
              System.out.println("It's a race of " + r.getDistance() + " lengths");
              
              System.out.println("Press Enter to run the race....");
              System.in.read();
              
              r.run();
          }
      }
      注意,在 清單 2 中,CountDownLatch 有兩個用途:首先,它同時釋放所有線程,模擬馬賽的起點,但隨后會設置一個門閂模擬馬賽的終點。這樣,“主” 線程就可以輸出結果。 為了讓馬賽有更多的輸出注釋,可以在賽場的 “轉彎處” 和 “半程” 點,比如賽馬跨過跑道的四分之一、二分之一和四分之三線時,添加 CountDownLatch。

      3、  Executor

      清單 1 和 清單 2 中的示例都存在一個重要的缺陷,它們要求您直接創建 Thread 對象。這可以解決一些問題,因為在一些 JVM 中,創建 Thread 是一項重量型的操作,重用現有 Thread 比創建新線程要容易得多。而在另一些 JVM 中,情況正好相反:Thread 是輕量型的,可以在需要時很容易地新建一個線程。當然,如果 Murphy 擁有自己的解決辦法(他通常都會擁有),那么您無論使用哪種方法對于您最終將部署的平臺都是不對的。
      JSR-166 專家組(參見 參考資料)在一定程度上預測到了這一情形。Java 開發人員無需直接創建 Thread,他們引入了 Executor 接口,這是對創建新線程的一種抽象。如清單 3 所示,Executor 使您不必親自對 Thread 對象執行 new 就能夠創建新線程:
      清單 3. Executor


      Executor exec = getAnExecutorFromSomeplace();
      exec.execute(new Runnable() { ... });
      使用 Executor 的主要缺陷與我們在所有工廠中遇到的一樣:工廠必須來自某個位置。不幸的是,與 CLR 不同,JVM 沒有附帶一個標準的 VM 級線程池。
      Executor 類實際上 充當著一個提供 Executor 實現實例的共同位置,但它只有 new 方法(例如用于創建新線程池);它沒有預先創建實例。所以您可以自行決定是否希望在代碼中創建和使用 Executor 實例。(或者在某些情況下,您將能夠使用所選的容器/平臺提供的實例。)
      ExecutorService 隨時可以使用
      盡管不必擔心 Thread 來自何處,但 Executor 接口缺乏 Java 開發人員可能期望的某種功能,比如結束一個用于生成結果的線程并以非阻塞方式等待結果可用。(這是桌面應用程序的一個常見需求,用戶將執行需要訪問數據庫的 UI 操作,然后如果該操作花費了很長時間,可能希望在它完成之前取消它。)
      對于此問題,JSR-166 專家創建了一個更加有用的抽象(ExecutorService 接口),它將線程啟動工廠建模為一個可集中控制的服務。例如,無需每執行一項任務就調用一次 execute(),ExecutorService 可以接受一組任務并返回一個表示每項任務的未來結果的未來列表

      4、  ScheduledExecutorServices

      盡管 ExecutorService 接口非常有用,但某些任務仍需要以計劃方式執行,比如以確定的時間間隔或在特定時間執行給定的任務。這就是 ScheduledExecutorService 的應用范圍,它擴展了 ExecutorService。
      如果您的目標是創建一個每隔 5 秒跳一次的 “心跳” 命令,使用 ScheduledExecutorService 可以輕松實現,如清單 4 所示:
      清單 4. ScheduledExecutorService 模擬心跳


      import java.util.concurrent.*;
       
      public class Ping
      {
          public static void main(String[] args)
          {
              ScheduledExecutorService ses =
                  Executors.newScheduledThreadPool(1);
              Runnable pinger = new Runnable() {
                  public void run() {
                      System.out.println("PING!");
                  }
              };
              ses.scheduleAtFixedRate(pinger, 5, 5, TimeUnit.SECONDS);
          }
      }
      這項功能怎么樣?不用過于擔心線程,不用過于擔心用戶希望取消心跳時會發生什么,也不用明確地將線程標記為前臺或后臺;只需將所有的計劃細節留給 ScheduledExecutorService。
      順便說一下,如果用戶希望取消心跳,scheduleAtFixedRate 調用將返回一個 ScheduledFuture 實例,它不僅封裝了結果(如果有),還擁有一個 cancel 方法來關閉計劃的操作。

      5、  Timeout 方法

      為阻塞操作設置一個具體的超時值(以避免死鎖)的能力是 java.util.concurrent 庫相比起早期并發特性的一大進步,比如監控鎖定。
      這些方法幾乎總是包含一個 int/TimeUnit 對,指示這些方法應該等待多長時間才釋放控制權并將其返回給程序。它需要開發人員執行更多工作 — 如果沒有獲取鎖,您將如何重新獲取? — 但結果幾乎總是正確的:更少的死鎖和更加適合生產的代碼。(關于編寫生產就緒代碼的更多信息,請參見 參考資料 中 Michael Nygard 編寫的 Release It!。)

      6、  結束語

      java.util.concurrent 包還包含了其他許多好用的實用程序,它們很好地擴展到了 Collections 之外,尤其是在 .locks 和 .atomic 包中。深入研究,您還將發現一些有用的控制結構,比如 CyclicBarrier 等。
      與 Java 平臺的許多其他方面一樣,您無需費勁地查找可能非常有用的基礎架構代碼。在編寫多線程代碼時,請記住本文討論的實用程序和 上一篇文章 中討論的實用程序。

      相關教程
      江苏快3 新疆乌鲁木齐 | 淮北 | 克孜勒苏 | 泰兴 | 如皋 | 大兴安岭 | 和田 | 云南昆明 | 万宁 | 台山 | 宁波 | 丽江 | 宜昌 | 马鞍山 | 泗洪 | 马鞍山 | 盘锦 | 珠海 | 石嘴山 | 德清 | 保定 | 伊春 | 三明 | 南充 | 巴中 | 辽宁沈阳 | 招远 | 榆林 | 永新 | 黑河 | 常德 | 高雄 | 延安 | 神木 | 鸡西 | 兴安盟 | 曹县 | 象山 | 佳木斯 | 潜江 | 甘肃兰州 | 通化 | 朔州 | 新余 | 海南海口 | 陵水 | 揭阳 | 诸城 | 防城港 | 崇左 | 郴州 | 张家口 | 遂宁 | 淮南 | 柳州 | 江苏苏州 | 固原 | 大理 | 诸暨 | 丹东 | 衡阳 | 伊犁 | 安阳 | 宜昌 | 安康 | 塔城 | 广元 | 攀枝花 | 台中 | 象山 | 开封 | 舟山 | 扬州 | 天门 | 淮南 | 大同 | 宝应县 | 慈溪 | 德阳 | 常德 | 东台 | 呼伦贝尔 | 沧州 | 济源 | 青州 | 诸城 | 咸阳 | 衡水 | 项城 | 黔南 | 运城 | 梧州 | 崇左 | 南京 | 启东 | 库尔勒 | 阳春 | 汉川 | 锦州 | 吉林 | 芜湖 | 五指山 | 日土 | 吉林长春 | 邵阳 | 阿拉尔 | 阳江 | 宿州 | 资阳 | 来宾 | 广饶 | 福建福州 | 惠州 |