bomberlhl

          統計

          留言簿(1)

          閱讀排行榜

          評論排行榜

          【轉】范例解說Java里的線程概念與線程同步技術

          線程 是一段完成某個特定功能的代碼,程序中的執行線程。Java 虛擬機允許應用程序并發地運行多個執行線程。
          每個線程都有一個優先級,高優先級線程的執行優先于低優先級線程。
          進程不同的是,由同名類生成的多個線程共享相同的內存空間和系統資源。

          線程與進程的區別:
          一個線程是一個程序內部的順序控制流。
          1. 進程:每個進程都有獨立的代碼和數據空間(進程上下文) ,進程切換的開銷大。線程:同一類線程共享代碼和數據空間,每個線程有獨立的運行棧和程序計數器(PC),線程切換的開銷小。
          2. 一個進程中可以包含多個線程。

          本文將介紹以下線程方面的知識:
          1,線程的創建
          2,線程的狀態
          3,線程同步
          4,線程組

          理解線程的最有效的方法是通過實例來理解。下面我們將通過 售貨員售書 為例,由淺入深地介紹線程的創建,通信,鎖機制等概念。

          售貨員售書
          我們假設一下售貨員售書的操作流程:
          1,我們假設有20本書,交給2個售貨員去賣。
          2,售貨員可以賣掉任何一本尚未賣出去的書。換句話說,同一本書若被其中一位售出去了,則不能被另外一位再售出了。


          清單1:
          文件名說明
          Book.java 書籍類
          SellBookRunnable.java 售書類,線程的創建方法之一,該類實現了Runnable 接口,并實現了 run 方法。
          SellBookThread.java 售書類,線程的創建方法之一,該類聲明為 Thread 的子類,并重寫 Thread 類的 run 方法。
          CallSellBook.java 調用類。該類分別介紹了2種不同線程創建的調用方法。

          Book.java
          1. publicclass Book {   
          2. private String name;
          3. privateboolean sold = false;   
          4. public Book(String name) {   
          5. this.name = name;
          6.     }   
          7. public String getName() {
          8. return name;
          9.     }   
          10. publicvoid setName(String name) {   
          11. this.name = name;   
          12.     }   
          13. publicboolean isSold() {   
          14. return sold;
          15.     }   
          16. publicvoid setSold(boolean sold) {   
          17. this.sold = sold;   
          18.     }   
          19. }  



          SellBookRunnable.javatil.List;
          1. publicclass SellBookRunnable implements Runnable {   
          2. private String saleMan;
          3. private List<Book> bookList;
          4. public SellBookRunnable(String saleMan, List<Book> bookList) {
          5. this.saleMan = saleMan;   
          6. this.bookList = bookList;   
          7.     }   
          8. publicvoid run() {   
          9. for (int i = 0; i < bookList.size(); i++) {
          10.             Book book = bookList.get(i);   
          11.             sellBook(book);   
          12.         }   
          13.     }   
          14. /**  
          15.      * 售貨員賣書。我們這樣描述售貨員的賣書過程。  
          16.      *   
          17.      * @param book Book  
          18.      */
          19. privatevoid sellBook(Book book) {   
          20. //從開始售書-到售書完成,使用synchronized (book)保證book不被其他售貨員售出
          21. synchronized (book) {
          22. if (book.isSold()) {   
          23. return;
          24.             } else {
          25. try {
          26. //為了讓各線程有執行機會,設置平均售書時間為0.5秒
          27.                     Thread.sleep(500);   
          28.                 } catch (Exception e) {   
          29.                 }   
          30. //設置已售標志
          31.                 book.setSold(true);   
          32. //打印該書已售信息
          33.                 System.out.println("[" + saleMan + "]" + book.getName() + " sold out:"
          34.                         + book.isSold() + ". by "
          35.                         + Thread.currentThread().getName());
          36.             }   
          37.         }   
          38.     }   
          39. }  



          SellBookThread.java

          1. import java.util.List;
          2. publicclass SellBookThread extends Thread {   
          3. private String saleMan;
          4. private List<Book> bookList;
          5. public SellBookThread(String saleMan, List<Book> bookList) {
          6. this.saleMan = saleMan;   
          7. this.bookList = bookList;   
          8.     }   
          9. publicvoid run() {   
          10. for (int i = 0; i < bookList.size(); i++) {
          11.             Book book = bookList.get(i);   
          12.             sellBook(book);   
          13.         }   
          14.     }   
          15. /**  
          16.      * 售貨員賣書。我們這樣描述售貨員的賣書過程。  
          17.      *   
          18.      * @param book Book  
          19.      */
          20. privatevoid sellBook(Book book) {   
          21. //從開始售書-到售書完成,使用synchronized (book)保證book不被其他售貨員售出
          22. synchronized (book) {
          23. if (book.isSold()) {   
          24. return;
          25.             } else {
          26. try {
          27. //為了讓各線程有執行機會,設置平均售書時間為0.5秒
          28.                     Thread.sleep(500);   
          29.                 } catch (Exception e) {   
          30.                 }   
          31. //設置已售標志
          32.                 book.setSold(true);   
          33. //打印該書已售信息
          34.                 System.out.println("[" + saleMan + "]" + book.getName() + " sold out:"
          35.                         + book.isSold() + ". by "
          36.                         + Thread.currentThread().getName());
          37.             }   
          38.         }   
          39.     }   
          40. }  



          CallSellBook.java

          1. import java.util.ArrayList;
          2. import java.util.List;
          3. //該類調用SellBookXxx類
          4. publicclass CallSellBook {   
          5. /**  
          6.      * 用線程模擬這個售書的過程  
          7.      */
          8. publicstaticvoid main(String[] args) {   
          9. //方法1:
          10.         callSellBookThread();   
          11. //or
          12. //方法2:
          13. //callSellBookRunnable();
          14.     }   
          15. //調用SellBookRunnable(Runnable接口實現類)模擬售書過程
          16. publicstaticvoid callSellBookThread() {   
          17.         List <Book>bookList = getBookListForSale();
          18. //將預售書籍清單交給售貨員SaleMan1
          19.         Thread t1 = new SellBookThread("SaleMan1", bookList);   
          20. //將預售書籍清單交給售貨員SaleMan2
          21.         Thread t2 = new SellBookThread("SaleMan2", bookList);   
          22. //售貨員SaleMan1開始售書
          23.         t1.start();   
          24. //售貨員SaleMan2開始售書
          25.         t2.start();   
          26.     }   
          27. //調用SellBookRunnable(Runnable接口實現類)模擬售書過程
          28. publicstaticvoid callSellBookRunnable() {   
          29.         List <Book>bookList = getBookListForSale();
          30. //將預售書籍清單交給售貨員SaleMan1
          31.         Thread t1 = new Thread(new SellBookRunnable("SaleMan1", bookList));   
          32. //將預售書籍清單交給售貨員SaleMan2
          33.         Thread t2 = new Thread(new SellBookRunnable("SaleMan2", bookList));   
          34. //售貨員SaleMan1開始售書
          35.         t1.start();   
          36. //售貨員SaleMan2開始售書
          37.         t2.start();   
          38.     }   
          39. //準備預售書籍
          40. publicstatic List<Book> getBookListForSale() {
          41.         List <Book>bookList = new ArrayList();   
          42. for (int i = 0; i < 20; i++) {   
          43.             Book book = new Book("Book" + i);   
          44.             bookList.add(book);   
          45.         }   
          46. return bookList;   
          47.     }   
          48. }  


          執行CallSellBook
          [SaleMan1]Book0 sold out:true. by Thread-0
          [SaleMan2]Book1 sold out:true. by Thread-1
          [SaleMan2]Book2 sold out:true. by Thread-1
          [SaleMan2]Book3 sold out:true. by Thread-1
          [SaleMan2]Book4 sold out:true. by Thread-1
          [SaleMan2]Book5 sold out:true. by Thread-1
          [SaleMan1]Book6 sold out:true. by Thread-0
          [SaleMan1]Book7 sold out:true. by Thread-0
          [SaleMan1]Book8 sold out:true. by Thread-0
          [SaleMan1]Book9 sold out:true. by Thread-0
          [SaleMan1]Book10 sold out:true. by Thread-0
          [SaleMan1]Book11 sold out:true. by Thread-0
          [SaleMan2]Book12 sold out:true. by Thread-1
          [SaleMan2]Book13 sold out:true. by Thread-1
          [SaleMan2]Book14 sold out:true. by Thread-1
          [SaleMan2]Book15 sold out:true. by Thread-1
          [SaleMan2]Book16 sold out:true. by Thread-1
          [SaleMan2]Book17 sold out:true. by Thread-1
          [SaleMan1]Book18 sold out:true. by Thread-0
          [SaleMan1]Book19 sold out:true. by Thread-0
          線程的創建
          創建新執行線程有兩種方法。
          方法一種方法是將類聲明為 Thread 的子類。該子類應重寫 Thread 類的 run 方法。事實上類Thread本身也實現了接口Runnable,所以我們可以同過繼承Thread類實現線程體。
          參考:SellBookThread.javaCallSellBook.java
          另一種方法是聲明實現 Runnable 接口的類。該類然后實現 run 方法。
          參考:SellBookRunnable.javaCallSellBook.java



          線程的狀態
          線程有四種狀態:創建狀態(New),可運行狀態(Runnable),阻塞狀態(Blocked),死亡狀態(Dead)。

          創建狀態(New):
          當執行完
          Thread t1 = new SellBookThread("SaleMan1", bookList);
          語句之后,則t1處于創建狀態(New)。此時t1并未真正運行。

          可運行狀態(Runnable):
          當Thread t1被創建,并執行完
          t1.start();
          語句之后,t1就處于可運行狀態(Runnable)。此時,系統為線程t1分配其所需的系統資源。并對t1加以調用(或者根據任務調度情況準備調用)。

          阻塞狀態(Blocked):
          由于以下原因:
          1) 調用了sleep()方法;
          2) 調用了suspend()方法(該方法已不推薦使用);
          3) 為等待條件鎖,調用wait()方法等;
          4) 輸入輸出,或消息發生阻塞;

          使得線程處于阻塞狀態(Blocked)。處于該狀態的線程即使處理器空閑,也不會得到執行。

          死亡狀態(Dead):
          死亡狀態(Dead)可以為自然死亡(線程運行完畢),或者調用了stop()方法(該方法已不推薦使用)。


          線程的優先級:
          可以通過Thread類的    
          void setPriority(int newPriority)
          方法為線程設置優先級。但是不能保證高優先級的線程就會被先運行。

          線程組:
          可以通過
          ThreadGroup group = new ThreadGroup(groupName);
          Thread t1 = new Thread(ThreadGroup g, Runnable r1);
          Thread t1 = new Thread(ThreadGroup g, Runnable r2);
          等方法把多個線程加到一個線程組里去,這樣可以通過ThreadGroup對這些線程進行某些統一操作,
          例如:group.interrupt();中斷該組所有線程。


          線程unchecked異常處理器:
          可以通過:
          public void static Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler)
          方法為所有線程指定一個unchecked異常處理器,該處理器必須實現UncaughtExceptionHandler接口。


          線程同步:
          線程同步指多個線程同時訪問某資源時,采用一系列的機制以保證同時最多只能一個線程訪問該資源。
          線程同步是多線程中必須考慮和解決的問題,因為很可能發生多個線程同時訪問(主要是寫操作)同一資源,如果不進行線程同步,很可能會引起數據混亂,造成線程死鎖等問題。

          使用synchronized同步線程。
          在J2SE5.0之前,只能使用synchronized來同步線程。可以使用synchronized來同步代碼塊或者方法。
          同步代碼塊例:
          synchronized(欲同步的對象obj) {需要同步的代碼塊}可以同步代碼塊。

          參考:SellBookThread.java
          1. privatevoid sellBook(Book book) {   
          2. synchronized (book) {
          3.             ...   
          4.         }   
          5.     }  

          該例synchronized (book) 表示若多個線程同時訪問時,只讓其中一個線程最先取得book對象,其它線程則阻塞直到代碼塊執行完畢book對象被釋放后,其它線程才能取得該book對象繼續執行。
          很多情況下,可以使用synchronized (this){...}來同步代碼塊。但需要注意的是,使用this作為同步對象的話,如果同一個類中存在多個synchronized (this){...}代碼塊,其中任何一個synchronized(this)代碼塊處于被執行狀態,則其它線程對其他synchronized(this)代碼塊的訪問也會受到阻塞。

          同步方法例:
          1. synchronizedprivatevoid sellBook(Book book) {   
          2. ...   
          3. }  

          這種方法其實相當于
          1. privatevoid sellBook(Book book) {   
          2. synchronized(this) {   
          3.         ...   
          4.     }   
          5. }  

          由于默認采用this作為同步對象,所以當一個類中有多個synchronized方法時,同樣會存在以上問題:即如果有一個線程訪問其中某個synchronized方法時,直到該方法執行完畢,其它線程對其它synchronized方法的訪問也將受到阻塞。
          有關synchronized詳細說明我們將在其它文章中加以說明。


          使用java.util.concurrent.locks.ReentrantLock和java.util.concurrent.locks.ReentrantReadWriteLock類同步線程。
          J2SE5.0加入了ReentrantLock和ReentrantReadWriteLock可以對線程進行同步,這里舉一個最簡單的例子對其加以說明:
          1. class X {
          2. privatefinal ReentrantLock lock = new ReentrantLock();   
          3. // ...
          4. publicvoid m() {    
          5.      lock.lock();  // block until condition holds
          6. try {
          7. // ... method body
          8.      } finally {
          9.        lock.unlock()   
          10.      }   
          11.    }   
          12.  }   



          其它J2SE5.0新導入的有關線程的相關接口/類:
          java.util.concurrent.Future
          Future接口可以保持/取得異步執行的結果值

          java.util.concurrent.Callable
          類似于Runnable接口。但Runnable不能返回值,也不能拋出checked異常

          java.util.concurrent.ExecutorService
          該接口繼承了Executor接口。可以通過submit方法把Runnable,Callable對象轉換為Future 形式。

          java.util.concurrent.FutureTask
          該類實現了Runnable和Future接口。提供異步執行的取消以及異步執行結果的取得等功能。

          java.util.concurrent.Executor
          執行指定的Runnable對象

          java.util.concurrent.Executors
          工具類。提供靜態方法可以創建Executor,ExecutorService,Callable等對象。可以通過newCachedThreadPool()等方法簡單創建線程池。


          posted on 2009-12-14 19:29 異域流浪 閱讀(253) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 新源县| 高雄市| 鄂温| 东乡族自治县| 温宿县| 抚顺市| 理塘县| 保定市| 昌平区| 安庆市| 阳江市| 阳泉市| 奎屯市| 保亭| 扶风县| 民乐县| 瑞丽市| 社旗县| 东辽县| 花莲县| 临澧县| 武城县| 赤峰市| 丁青县| 肥东县| 永德县| 衡阳县| 张家口市| 岚皋县| 临安市| 邵阳市| 崇文区| 渝北区| 阿坝| 海兴县| 舟山市| 扶沟县| 内乡县| 白玉县| 衡阳县| 成武县|