1. 程式人生 > >JAVA執行緒與執行緒、程序與程序間通訊

JAVA執行緒與執行緒、程序與程序間通訊

I.執行緒與執行緒間通訊

一、基本概念以及執行緒與程序之間的區別聯絡:
關於程序和執行緒,首先從定義上理解就有所不同

1、程序是什麼?
是具有一定獨立功能的程式、它是系統進行資源分配和排程的一個獨立單位,重點在系統排程和單獨的單位,也就是說程序是可以獨 立執行的一段程式。
2、執行緒又是什麼?
執行緒程序的一個實體,是CPU排程和分派的基本單位,他是比程序更小的能獨立執行的基本單位,執行緒自己基本上不擁有系統資源。
在執行時,只是暫用一些計數器、暫存器和棧 。

他們之間的關係

1、一個執行緒只能屬於一個程序,而一個程序可以有多個執行緒,但至少有一個執行緒(通常說的主執行緒)。
2、資源分配給程序,同一程序的所有執行緒共享該程序的所有資源。
3、執行緒在執行過程中,需要協作同步。不同程序的執行緒間要利用訊息通訊的辦法實現同步。
4、處理機分給執行緒,即真正在處理機上執行的是執行緒。
5、執行緒是指程序內的一個執行單元,也是程序內的可排程實體。

從三個角度來剖析二者之間的區別
1、排程:執行緒作為排程和分配的基本單位,程序作為擁有資源的基本單位。
2、併發性:不僅程序之間可以併發執行,同一個程序的多個執行緒之間也可以併發執行。
3、擁有資源:程序是擁有資源的一個獨立單位,執行緒不擁有系統資源,但可以訪問隸屬於程序的資源。

二、多執行緒間通訊方式:

1、共享變數

2、wait/notify機制

3、Lock/Condition機制

4、管道

三、共享變數

執行緒間傳送訊號的一個簡單方式是在共享物件的變數裡設定訊號值。執行緒A在一個同步塊裡設定boolean型成員變數hasDataToProcess為true,執行緒B也在同步塊裡讀取hasDataToProcess這個成員變數。這個簡單的例子使用了一個持有訊號的物件,並提供了set和check方法:

public class MySignal{

  protected boolean hasDataToProcess = false;

  public synchronized boolean hasDataToProcess(){
    return this.hasDataToProcess;
  }

  public synchronized void setHasDataToProcess(boolean hasData){
    this.hasDataToProcess = hasData;
  }

}

執行緒A和B必須獲得指向一個MySignal共享例項的引用,以便進行通訊。如果它們持有的引用指向不同的MySingal例項,那麼彼此將不能檢測到對方的訊號。需要處理的資料可以存放在一個共享快取區裡,它和MySignal例項是分開存放的。

四、wait()/notify機制

為了實現執行緒通訊,我們可以使用Object類提供的wait()、notify()、notifyAll()三個方法。呼叫wait()方法會釋放對該同步監視器的鎖定。這三個方法必須由同步監視器物件來呼叫,這可分成兩種情況:

  • 對於使用synchronized修飾的同步方法,因為該類的預設例項是(this)就是同步監視器,所以可以直接呼叫這三使用個方法。
  • 對於synchronized修飾的同步程式碼塊,同步監視器是synchronized括號裡的物件,所以必須使用該物件呼叫這三個方法。

假設系統中有兩條執行緒,這兩條執行緒分別代表取錢者和存錢者。現在系統有一種特殊的要求,系統要求存款者和取錢者不斷的實現存款和取錢動作,而且要求每當存款者將錢存入指定賬戶後,取錢者立即將錢取走.不允許存款者兩次存錢,也不允許取錢者兩次取錢。

我們通過設定一個旗標來標識賬戶中是否已有存款,有就為true,沒有就標為false。具體程式碼如下:

首先我們定義一個Account類,這個類中有取錢和存錢的兩個方法,由於這兩個方法可能需要併發的執行取錢、存錢操作,所有將這兩個方法都修改為同步方法.(使用synchronized關鍵字)。

public class Account {  
    private String accountNo;  
    private double balance;  
    //標識賬戶中是否有存款的旗標  
    private boolean flag=false;  
      
    public Account() {  
        super();  
    }  
  
    public Account(String accountNo, double balance) {  
        super();  
        this.accountNo = accountNo;  
        this.balance = balance;  
    }   
      
    public synchronized void draw (double drawAmount){  
          
        try {  
              if(!flag){  
              this.wait();  
             }else {  
                 //取錢  
                 System.out.println(Thread.currentThread().getName()+" 取錢:"+drawAmount);  
                 balance=balance-drawAmount;  
                 System.out.println("餘額 : "+balance);  
                 //將標識賬戶是否已有存款的標誌設為false  
                 flag=false;  
                 //喚醒其它執行緒  
                 this.notifyAll();         
             }  
            } catch (Exception e) {  
                e.printStackTrace();  
        }  
    }  
      
      
   public synchronized void deposit(double depositAmount){  
      try {  
              if(flag){  
                this.wait();  
              }  
              else{  
                  System.out.println(Thread.currentThread().getName()+"存錢"+depositAmount);  
                  balance=balance+depositAmount;  
                  System.out.println("賬戶餘額為:"+balance);  
                  flag=true;  
                  //喚醒其它執行緒  
                  this.notifyAll();  
              }  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
        }  
   }  
  
}  

接下來建立兩個執行緒類,分別為取錢和存錢執行緒!

取錢執行緒類:

  1. publicclass DrawThread implements Runnable {  
  2.     private Account account;  
  3.     privatedouble drawAmount;  
  4.     public DrawThread(Account account, double drawAmount) {  
  5.         super();  
  6.         this.account = account;  
  7.         this.drawAmount = drawAmount;  
  8.     }  
  9.     publicvoid run() {  
  10.         for(int i=0;i<100;i++){  
  11.            account.draw(drawAmount);      
  12.         }  
  13.     }  
  14. }  

存錢執行緒類:

  1. publicclass depositThread implements Runnable{  
  2.     private Account account;  
  3.     privatedouble depositAmount;  
  4.     public depositThread(Account account, double depositAmount) {  
  5.         super();  
  6.         this.account = account;  
  7.         this.depositAmount = depositAmount;  
  8.     }  
  9.     publicvoid run() {  
  10.     for(int i=0;i<100;i++){  
  11.          account.deposit(depositAmount);  
  12.       }  
  13.     }  
  14. }  

最後我們測試一下這個取錢和存錢的操作!

  1. publicclass TestDraw {  
  2.     publicstaticvoid main(String[] args) {  
  3.         //建立一個賬戶
  4.         Account account=new Account();  
  5.         new Thread(new DrawThread(account, 800),"取錢者").start();  
  6.         new Thread(new depositThread(account, 800),"存款者甲").start();  
  7.         new Thread(new depositThread(account, 800),"存款者乙").start();  
  8.         new Thread(new depositThread(account, 800),"存款者丙").start();  
  9.     }  
  10. }  

大致的輸出結果:

  1. 存款者甲存錢800.0
  2. 賬戶餘額為:800.0
  3. 取錢者 取錢:800.0
  4. 餘額 : 0.0
  5. 存款者丙存錢800.0
  6. 賬戶餘額為:800.0
  7. 取錢者 取錢:800.0
  8. 餘額 : 0.0
  9. 存款者甲存錢800.0
  10. 賬戶餘額為:800.0
  11. 取錢者 取錢:800.0
  12. 餘額 : 0.0
  13. 存款者丙存錢800.0
  14. 賬戶餘額為:800.0
  15. 取錢者 取錢:800.0
  16. 餘額 : 0.0
  17. 存款者甲存錢800.0
  18. 賬戶餘額為:800.0
  19. 取錢者 取錢:800.0
  20. 餘額 : 0.0
  21. 存款者丙存錢800.0
  22. 賬戶餘額為:800.0
  23. 取錢者 取錢:800.0
  24. 餘額 : 0.0
  25. 存款者甲存錢800.0
  26. 賬戶餘額為:800.0
  27. 取錢者 取錢:800.0
  28. 餘額 : 0.0
  29. 存款者丙存錢800.0
  30. 賬戶餘額為:800.0
  31. 取錢者 取錢:800.0
  32. 餘額 : 0.0
  33. 存款者甲存錢800.0
  34. 賬戶餘額為:800.0
  35. 取錢者 取錢:800.0
  36. 餘額 : 0.0

五、Lock/Condition機制

如何程式不使用synchronized關鍵字來保持同步,而是直接適用Lock對像來保持同步,則系統中不存在隱式的同步監視器物件,也就不能使用wait()、notify()、notifyAll()來協調執行緒的執行.

當使用LOCK物件保持同步時,JAVA為我們提供了Condition類來協調執行緒的執行。關於Condition類,JDK文件裡進行了詳細的解釋.,再次就不囉嗦了。

我們就拿Account類進行稍微的修改 一下吧!

  1. import java.util.concurrent.locks.Condition;  
  2. import java.util.concurrent.locks.Lock;  
  3. import java.util.concurrent.locks.ReentrantLock;  
  4. publicclass Account {  
  5.     //顯示定義Lock物件
  6.     privatefinal Lock lock=new ReentrantLock();  
  7.     //獲得指定Lock物件對應的條件變數
  8.     privatefinal  Condition con=lock.newCondition();     
  9.     private String accountNo;  
  10.     privatedouble balance;  
  11.     //標識賬戶中是否有存款的旗標
  12.     privateboolean flag=false;  
  13.     public Account() {  
  14.         super();  
  15.     }  
  16.     public Account(String accountNo, double balance) {  
  17.         super();  
  18.         this.accountNo = accountNo;  
  19.         this.balance = balance;  
  20.     }   
  21.     publicvoid draw (double drawAmount){  
  22.         //加鎖
  23.         lock.lock();  
  24.         try {  
  25.               if(!flag){  
  26. //            this.wait();
  27.               con.await();  
  28.              }else {  
  29.                  //取錢
  30.                  System.out.println(Thread.currentThread().getName()+" 取錢:"+drawAmount);  
  31.                  balance=balance-drawAmount;  
  32.                  System.out.println("餘額 : "+balance);  
  33.                  //將標識賬戶是否已有存款的標誌設為false
  34.                  flag=false;  
  35.                  //喚醒其它執行緒
  36. //               this.notifyAll();  
  37.                  con.signalAll();  
  38.              }  
  39.             } catch (Exception e) {  
  40.                 e.printStackTrace();  
  41.         }  
  42.             finally{  
  43.                 lock.unlock();  
  44.             }  
  45.     }  
  46.    publicvoid deposit(double depositAmount){  
  47.        //加鎖
  48.        lock.lock();  
  49.        try {  
  50.               if(flag){  
  51. //              this.wait();
  52.                   con.await();  
  53.               }  
  54.               else{  
  55.                   System.out.println(Thread.currentThread().getName()+"存錢"+depositAmount);  
  56. 相關推薦

    談談C#多執行開發:並行併發非同步程式設計

    閱讀導航 一、使用Task 二、並行程式設計 三、執行緒同步 四、非同步程式設計模型 五、多執行緒資料安全 六、異常處理   概述 現代程式開發過程中不可避免會使用到多執行緒相關的技術,之所以要使用多執行緒,主要原因或目的大致有以下幾個: 1、 業務特性決定程式就是多工的,比如,一邊採集資料、一邊分

    Java配置檔案Properties的讀取寫入更新操作

    /**   * 實現對Java配置檔案Properties的讀取、寫入與更新操作   */    package test;     &nbs

    Java 類的熱替換 —— 概念設計實現

    轉自:https://www.ibm.com/developerworks/cn/java/j-lo-hotswapcls/index.html 構建基於 Java 的線上升級系統 孫 鳴 和 鄧 輝 2010 年 1 月 14 日釋出 WeiboGoogle+用電子郵件傳送本頁面

    Java HttpClient(二:連線狀態管理認證cache)

    參考文獻:http://hc.apache.org/httpcomponents-client-ga/tutorial/html/ 文章目錄 2.連線管理 2.1 Http連線路由 2.2 Http連線管理 2.2.1

    Java中Date轉換為DatetimeStringDate的相互轉換

    本轉換在專案中經常遇見,現簡要地說明: (1) Date轉換為Datetime Datetime在java資料庫中對應的是Timestamp,轉換如下: //java.util.Date轉換為Timestamp Date date = new Date();

    同步異步阻塞非阻塞

    阻塞與非阻塞 就會 結束 檢查 通信機制 得到 node 分布 好書 “阻塞”與"非阻塞"與"同步"與“異步"不能簡單的從字面理解,提供一個從分布式系統角度的回答。1.同步與異步同步和異步關註的是消息通信機制 (synchronous communication/ a

    進程線程並行並發的理解

    實體 定義 命令 計數器 執行 大於 運行 系統 其它 進程與線程 1.定義 進程是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位. 線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本

    幾個例子理解對稱加密非對稱加密公鑰私鑰簽名驗籤數字證書HTTPS加密方式

    # 原創,轉載請留言聯絡 為什麼會出現這麼多加密啊,公鑰私鑰啊,簽名啊這些東西呢?說到底還是保證雙方通訊的安全性與完整性。例如小明發一封表白郵件給小紅,他總不希望給別人看見吧。而各種各樣的技術就是為了保障通訊的安全。(本文務必從上到下看) 1.對稱加密與非對稱加密 對稱加密: 對稱加密是

    移動端網頁開發經驗心得-解析度內容快取

    智慧手機發展確實很迅速,像今年,我的大部分工作就都在移動端網頁上。 再往前些年,看到的手機版/移動版網頁,限制於瀏覽器與手機效能,2g網路速度等 網頁設計無非是藍、黑、白,介面單調,並且要儘可能的設計簡單。 現在情況就大不相同了,軟體上webkit核心瀏覽器大行其道,硬體突飛猛進,網速

    C++STL中vector容器 begin()end()函式front()back()

    begin函式: 函式原型: iterator begin(); const_iterator begin(); 功能: 返回一個當前vector容器中起始元素的迭代器。 end函式: 函式原型: iterator end(); const_iterat

    C#之基礎篇①(VS快捷鍵WriteLine()Write()區別ReadKey()ReadLine()區別double,float,decimal區別)

         今天我們來分享一下VS視訊中第一講內容,這篇內容主要分享的是VS工具的使用以及簡單的資訊顯示、變數宣告。 一、導圖類: 二、程式碼類 2.1、顯示資訊 Console.WriteLine("************

    線相交矩形相交判斷

    /// /// 只要線與矩形有一條線有相交,則線與矩形相交 /// public class LineWithRect : MonoBehaviour { public Rect rect = new Rect(0, 0, 100, 100); public

    人臉影象識別NLP情感分析語言翻譯API呼叫

    API是一套用於構建應用軟體程式的規範、協議和工具。以下所有的API可歸類到人臉和影象識別;文字分析+NLP+情感分析;語言翻譯 一、人臉和影象識別 1.Animetrics Face Recogn

    jquery選擇器中的空格大於號>加號+波浪號~的區別

    概念 空格:$('parent childchild')表示獲取parent下的所有的childchild節點 大於號:$('parent > childchild')表示獲取parent下的所有下一級childchild 加號:$('pre + nextbr

    jquery選擇器空格大於號加號波浪號的區別

    轉自:http://my.oschina.net/jsonavaj/blog/62630 空格:$('parent childchild')表示獲取parent下的所有的childchild節點(所有的子孫)。 大於號:$('parent > child')表示獲取

    聊聊阻塞非阻塞同步非同步I/O模型

    1. 概念理解 在進行網路程式設計時,我們常常見到同步(Sync)/非同步(Async),阻塞(Block)/非阻塞(Unblock)四種呼叫方式: 同步/非同步主要針對C端:  同步: 所謂同步,就是在c端發出一個功能呼叫時,在沒有得到結果之前,該呼叫就不返回。也就是必須一件一件事做,等前一件做完了才能做

    /etc/profile/etc/bashrc互動式非互動式loginnon-login shell的區別

    線上的memcached又掛了,仍然沒有得到core檔案。排查原因,同事發現啟動memcached的指令碼存在可疑問題。 問題一:沒有設定memcached工作目錄,有可能core dump時沒有工作

    網路程式設計中阻塞非阻塞同步非同步I/O模型的理解

    1. 概念理解      在進行網路程式設計時,我們常常見到同步(Sync)/非同步(Async),阻塞(Block)/非阻塞(Unblock)四種呼叫方式:同步:所謂同步,就是在發出一個功能呼叫時,在沒有得到結果之前,該呼叫就不返回。也就是必須一件一件事做,等前一件做完了才能做下一件事。 例如

    [C++]STL中vector容器 begin()end()函式front()back()的用法

        本部落格轉自http://blog.csdn.net/duan19920101/article/details/51679517 一、begin函式 函式原型: iterator begin(); const_iterator begin(); 功能: 返回一個當

    C++STL中vector容器 begin()end()函式front()back()的用法

    一、begin函式 函式原型: iterator begin(); const_iterator begin(); 功能: 返回一個當前vector容器中起始元素的迭代器。 二、end函式 函式原型: iterator end(); const_iterator end(