多線程的通信方法


本文轉自:http://my.oschina.net/u/248570/blog/53226

第三部分屬於本人原創

一、進程通信方法

在說明線程通信前,有必要對進程通信進行說明;

進程間通信的方法主要有以下幾種:

  (1)管道(Pipe):管道可用於具有親緣關系進程間的通信,允許一個進程和另一個與它有共同祖先的進程之間進行通信。
  (2)命名管道(named pipe):命名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關 系 進程間的通信。命名管道在文件系統中有對應的文件名。命名管道通過命令mkfifo或系統調用mkfifo來創建。
  (3)信號(Signal):信號是比較復雜的通信方式,用於通知接受進程有某種事件發生,除了用於進程間通信外,進程還可以發送 信號給進程本身;linux除了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標准的信號函數sigaction(實際上,該 函數是基於BSD的,BSD為了實現可靠信號機制,又能夠統一對外接口,用sigaction函數重新實現了signal函數)。
  (4) 消息(Message)隊列:消息隊列是消息的鏈接表,包括Posix消息隊列system V消息隊列。有足夠權限的進程可以向隊列中添加消息,被賦予讀權限的進程則可以讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式字 節流以及緩沖區大小受限等缺
  (5)共享內存:使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。往往與其它通信機制,如信號量結合使用,來達到進程間的同步及互斥。
  (6)內存映射(mapped memory):內存映射允許任何多個進程間通信,每一個使用該機制的進程通過把一個共享的文件映射到自己的進程地址空間來實現它。
  (7)信號量(semaphore):主要作為進程間以及同一進程不同線程之間的同步手段。
  (8)套接口(Socket):更為一般的進程間通信機制,可用於不同機器之間的進程間通信。起初是由Unix系統的BSD分支開發出來的,但現在一般可以移植到其它類Unix系統上:Linux和System V的變種都支持套接字

 

二、線程通信方法

線程通信主要包括兩種方法:

(1)共享內存

共享內存的方法在前面的("生產者消費者"相關地點都有介紹);下面介紹另外一種形式:

通過內部類實現線程的共享變量

 

/** * 通過內部類實現線程的共享變量 * */
public
class Innersharethread { public static void main(String[] args) { Mythread mythread = new Mythread(); mythread.getThread().start(); mythread.getThread().start(); mythread.getThread().start(); mythread.getThread().start(); } } class Mythread { int index = 0; private class InnerThread extends Thread { public synchronized void run() { while (true) { System.out.println(Thread.currentThread().getName() + "is running and index is " + index++); } } } public Thread getThread() { return new InnerThread(); } } //在這其中內部類共享類公共類里面的index變量,並通過對公共類進行加鎖達到方法同步的目的。

 

 

 

(2)管道

主要分為一下步驟:

首先建立管道流,並將管道流的輸入輸出對象進行鏈接;

將管道流加入到生產對象(線程)中;

通過管道流引出輸入輸出流,並在線程中對這些流進行操作;

注:管道流的的read的方法是一種阻塞方法;

 

public class CommunicateWhitPiping {
    public static void main(String[] args) {
        /**
         * 創建管道輸出流
         */
        PipedOutputStream pos = new PipedOutputStream();
        /**
         * 創建管道輸入流
         */
        PipedInputStream pis = new PipedInputStream();
        try {
            /**
             * 將管道輸入流與輸出流連接 此過程也可通過重載的構造函數來實現
             */
            pos.connect(pis);
        } catch (IOException e) {
            e.printStackTrace();
        }
        /**
         * 創建生產者線程
         */
        Producer p = new Producer(pos);
        /**
         * 創建消費者線程
         */
        Consumer c = new Consumer(pis);
        /**
         * 啟動線程
         */
        p.start();
        c.start();
    }
}

/**
 * 生產者線程(與一個管道輸入流相關聯)
 * 
 */
class Producer extends Thread {
    private PipedOutputStream pos;

    public Producer(PipedOutputStream pos) {
        this.pos = pos;
    }

    public void run() {
        int i = 8;
        try {
            pos.write(i);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 消費者線程(與一個管道輸入流相關聯)
 * 
 */
class Consumer extends Thread {
    private PipedInputStream pis;

    public Consumer(PipedInputStream pis) {
        this.pis = pis;
    }

    public void run() {
        try {
            System.out.println(pis.read());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

(3)通過調用線程的公共接口

上圖所示為調用公共接口與Actor模型的區別,調用公共接口是線程A獲取線程B的引用,並通過調用線程B的方法,想B中輸入信息,從而達到線程消息傳遞的目的,它的缺陷也是顯而易見的,那就是在B中滯留的問題(方法必須在B中返回,A的流程才能繼續執行下去)!

三、其它

眾所周知,在java的多線程體系中存在這諸多問題,通信過程的內存共享往往會導致意想不到的錯誤,而管道流的阻塞方法和調用接口方法的同步性也會是得有些時候並發編程有些困難;現在流線的多線程框架為ACTOR體系;在c++中已經相關包的實現(http://c.chinaitlab.com/example/895427.html c++中ACTOR框架的具體介紹),而在java中的衍生語言(其實是基於jvm的語言)scala也提供了Actor機制,具體可進行相關的搜索

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM