gembin

          OSGi, Eclipse Equinox, ECF, Virgo, Gemini, Apache Felix, Karaf, Aires, Camel, Eclipse RCP

          HBase, Hadoop, ZooKeeper, Cassandra

          Flex4, AS3, Swiz framework, GraniteDS, BlazeDS etc.

          There is nothing that software can't fix. Unfortunately, there is also nothing that software can't completely fuck up. That gap is called talent.

          About Me

           

          Java 共享內存

          共享內存可以說是最有用的進程間通信方式,也是最快的IPC(Inter-Process Communication)形式。兩個不同進程A、B共享內存的意思是,同一塊物理內存被映射到進程A、B各自的進程地址 空間。進程A可以即時看到進程B對共享內存中數據的更新,反之亦然。由于多個進程共享同一塊內存區域,必然需要某種同步機制,互斥鎖和信號量都可以。

          采用共享內存通信的一個顯而易見的好處是效率高,因為進程可以直接讀寫內存,而不需要任何數據的拷貝。對于像管道和消息隊列等通信方式,則需要在內核和用 戶空間進行四次的數據拷貝,而共享內存則只拷貝兩次數據:一次從輸入文件到共享內存區,另一次從共享內存區到輸出文件。實際上,進程之間在共享內存時,并 不總是讀寫少量數據后就解除映射,有新的通信時,再重新建立共享內存區域。而是保持共享區域,直到通信完畢為止,這樣,數據內容一直保存在共享內存中,并 沒有寫回文件。共享內存中的內容往往是在解除映射時才寫回文件的。因此,采用共享內存的通信方式效率是非常高的。

          共享內存的使用有如下幾個特點:

          1. 可以被多個進程打開訪問;
          2. 讀寫操作的進程在執行讀寫操作時其他進程不能進行寫操作;
          3. 多個進程可以交替對某一共享內存執行寫操作;
          4. 一個進程執行了內存的寫操作后,不影響其他進程對該內存的訪問。同時其他進程對更新后的內存具有可見性。
          5. 在進程執行寫操作時如果異常退出,對其他進程寫操作禁止應自動解除。
          6. 相對共享文件,數據訪問的更方便更效率

          另外,共享內存的使用上有如下情況:

          獨占的寫操作,相應有獨占的寫操作等待隊列。獨占的寫操作本身不會發生數據的一致性問題。
          共享的寫操作,相應有共享的寫操作等待隊列。共享的寫操作則要注意防止發生數據的一致性問題。
          獨占的讀操作,相應有共享的讀操作等待隊列;
          共享的讀操作,相應有共享的讀操作等待隊列。

          共享內存在java中的實現
          在jdk1.4中提供的類MappedByteBuffer為我們實現共享內存提供了較好的方法。該緩 沖區實際上是一個磁盤文件的內存映像。二者的變化將保持同步,即內存數據發生變化會立 刻反映到磁盤文件中,這樣會有效的保證共享內存的實現。

          將 共享內存和磁盤文件建立聯系的是文件通道類:FileChannel。該類的加入是JDK為 了統一對外部設備(文件、網絡接口等)的訪問方法,并且加強了多線程對同一文件進行存 取的安全性。例如讀寫操作統一成read和write。這里只是用它來建立共享內存用,它建立 了共享內存和磁盤文件之間的一個通道。

          打 開一個文件建立一個文件通道可以用RandomAccessFile類中的方法getChannel。該 方法將直接返回一個文件通道。該文件通道由于對應的文件設為隨機存取文件,一方面可以 進行讀寫兩種操作,另一方面使用它不會破壞映像文件的內容(如果用FileOutputStream直 接打開一個映像文件會將該文件的大小置為0,當然數據會全部丟失)。這里,如果用 FileOutputStream和FileInputStream則不能理想的實現共享內存的要求,因為這兩個類同時 實現自由的讀寫操作要困難得多。

          下面的代碼實現了如上功能,它的作用類似UNIX系統中的mmap函數。

          // 獲得一個只讀的隨機存取文件對象
          RandomAccessFile RAFile = new RandomAccessFile(filename,"r");

          // 獲得相應的文件通道
          FileChannel fc = RAFile.getChannel();

          // 取得文件的實際大小,以便映像到共享內存
          int size = (int)fc.size();

          // 獲得共享內存緩沖區,該共享內存只讀
          MappedByteBuffer mapBuf = fc.map(FileChannel.MAP_RO,0,size);

          // 獲得一個可讀寫的隨機存取文件對象
          RAFile = new RandomAccessFile(filename,"rw");

          // 獲得相應的文件通道
          fc = RAFile.getChannel();

          // 取得文件的實際大小,以便映像到共享內存
          size = (int)fc.size();

          // 獲得共享內存緩沖區,該共享內存可讀寫
          mapBuf = fc.map(FileChannel.MAP_RW,0,size);

          // 獲取頭部消息:存取權限
          mode = mapBuf.getInt();

          如果多個應用映像同一文件名的共享內存,則意味著這多個應用共享了同一內存數據。 這些應用對于文件可以具有同等存取權限,一個應用對數據的刷新會更新到多個應用中。

          為了防止多個應用同時對共享內存進行寫操作,可以在該共享內存的頭部信息加入寫操 作標志。該共享內存的頭部基本信息至少有:
          int Length; // 共享內存的長度。
          int mode; // 該共享內存目前的存取模式。




          共享內存的頭部信息是類的私有信息,在多個應用可以對同一共享內存執行寫操作時, 開始執行寫操作和結束寫操作時,需調用如下方法:
          public boolean StartWrite()
          {
          if(mode == 0) { // 標志為0,則表示可寫
          mode = 1; // 置標志為1,意味著別的應用不可寫該共享內存
          mapBuf.flip();
          mapBuf.putInt(mode); // 寫如共享內存的頭部信息
          return true;
          }
          else {
          return false; // 指明已經有應用在寫該共享內存,本應用不可寫該共享內存
          }
          }

          public boolean StopWrite()
          {
          mode = 0; // 釋放寫權限
          mapBuf.flip();
          mapBuf.putInt(mode); // 寫入共享內存頭部信息
          return true;
          }

          這里提供的類文件mmap.java封裝了共享內存的基本接口,讀者可以用該類擴展成自己 需要的功能全面的類。

          如 果執行寫操作的應用異常中止,那么映像文件的共享內存將不再能執行寫操作。為了 在應用異常中止后,寫操作禁止標志自動消除,必須讓運行的應用獲知退出的應用。在多線 程應用中,可以用同步方法獲得這樣的效果,但是在多進程中,同步是不起作用的。方法可 以采用的多種技巧,這里只是描述一可能的實現:采用文件鎖的方式。寫共享內存應用在獲 得對一個共享內存寫權限的時候,除了判斷頭部信息的寫權限標志外,還要判斷一個臨時的 鎖文件是否可以得到,如果可以得到,則即使頭部信息的寫權限標志為1(上述),也可以 啟動寫權限,其實這已經表明寫權限獲得的應用已經異常退出,這段代碼如下:
          // 打開一個臨時的文件,注意同一共享內存,該文件名要相同,可以在共享文件名后加后綴“.lock”。
          RandomAccessFile fis = new RandomAccessFile("shm.lock","rw");
          // 獲得文件通道
          FileChannel lockfc = fis.getChannel();
          // 獲得文件的獨占鎖,該方法不產生堵塞,立刻返回
          FileLock flock = lockfc.tryLock();
          // 如果為空,則表明已經有應用占有該鎖
          if(flock == null) {
          ...// 不能執行寫操作
          }
          else {
          ...// 可以執行寫操作
          }


          該鎖會在應用異常退出后自動釋放,這正是該處所需要的方法。

          3 共享內存在java中的應用
          共享內存在java應用中,經常有如下兩種種應用:

          永久對象配置。
          在 java服務器應用中,用戶可能會在運行過程中配置一些參數,而這些參數需要永久 有效,當服務器應用重新啟動后,這些配置參數仍然可以對應用起作用。這就可以用到該文 中的共享內存。該共享內存中保存了服務器的運行參數和一些對象運行特性。可以在應用啟 動時讀入以啟用以前配置的參數。

          查詢共享數據。
          一個應用是系統的服務進程,其系統的運行狀態記錄在共享內存中,其中運行狀態可能是不斷變化的。為了隨時了解系統的運行狀態,啟動另一個應用,該應用查詢該共享內存,匯報系統的運行狀態。

          可見,共享內存在java應用中還是很有用的,只要組織好共享內存的數據結構,共享內存就可以在應用開發中發揮很不錯的作用。

          posted on 2008-04-11 11:22 gembin 閱讀(3833) 評論(1)  編輯  收藏 所屬分類: JavaSE

          評論

          # re: Java 共享內存 2008-04-12 10:52 豆抓電影搜索

          共想?http://www.douzhua.com  回復  更多評論   

          導航

          統計

          常用鏈接

          留言簿(6)

          隨筆分類(440)

          隨筆檔案(378)

          文章檔案(6)

          新聞檔案(1)

          相冊

          收藏夾(9)

          Adobe

          Android

          AS3

          Blog-Links

          Build

          Design Pattern

          Eclipse

          Favorite Links

          Flickr

          Game Dev

          HBase

          Identity Management

          IT resources

          JEE

          Language

          OpenID

          OSGi

          SOA

          Version Control

          最新隨筆

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          free counters
          主站蜘蛛池模板: 府谷县| 灵石县| 登封市| 新沂市| 夏津县| 全南县| 定西市| 德庆县| 依安县| 大冶市| 台湾省| 达拉特旗| 大新县| 墨脱县| 贺兰县| 喀什市| 和顺县| 黔南| 新巴尔虎左旗| 四川省| 双峰县| 南漳县| 渝北区| 楚雄市| 永顺县| 西峡县| 瑞安市| 墨江| 云龙县| 武鸣县| 大城县| 安岳县| 鹰潭市| 阿瓦提县| 黄梅县| 福泉市| 贡山| 汾阳市| 福清市| 谢通门县| 涞源县|