熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> JSP教程 >> 正文

共享內存在Java中的實現和應用

2013-11-15 09:50:05  來源: JSP教程 

   共享內存對應應用開發的意義
  對熟知UNIX系統應用開發的程序員來說IPC(InterProcess Communication)機制是非常熟悉的IPC基本包括共享內存信號燈操作消息隊列信號處理等部分是開發應用中非常重要的必不可少的工具其中共享內存IPC機制的關鍵對於數據共享系統快速查詢動態配置減少資源耗費等均有獨到的優點
  
  對應UNIX系統來說共享內存分為一般共享內存和映像文件共享內存兩種而對應 Windows實際上只有映像文件共享內存一種所以java應用中也是只能創建映像文件共享內存
  
  在java語言中基本上沒有提及共享內存這個概念但是在某一些應用中共享內存確實非常有用例如采用java語言的分布式應用系統中存在著大量的分布式共享對象很多時候需要查詢這些對象的狀態以查看系統是否運行正常或者了解這些對象的目前的一些統計數據和狀態如果采用網絡通信的方式顯然會增加應用的額外負擔也增加了一些不必要的應用編程而如果采用共享內存的方式則可以直接通過共享內存查看對象的狀態數據和統計數據從而減少了一些不必要的麻煩
  
  共享內存的使用有如下幾個特點
  
  可以被多個進程打開訪問
  讀寫操作的進程在執行讀寫操作時其他進程不能進行寫操作
  多個進程可以交替對某一共享內存執行寫操作
  一個進程執行了內存的寫操作後不影響其他進程對該內存的訪問同時其他進程對更新後的內存具有可見性
  在進程執行寫操作時如果異常退出對其他進程寫操作禁止應自動解除
  相對共享文件數據訪問的方便性和效率有
  
  
  另外共享內存的使用上有如下情況
  
  獨占的寫操作相應有獨占的寫操作等待隊列獨占的寫操作本身不會發生數據的一致性問題
  共享的寫操作相應有共享的寫操作等待隊列共享的寫操作則要注意防止發生數據的一致性問題
  獨占的讀操作相應有共享的讀操作等待隊列
  共享的讀操作相應有共享的讀操作等待隊列
  
  
  一般情況下我們只是關心第一二種情況
  
   共享內存在java中的實現
  在jdk中提供的類MappedByteBuffer為我們實現共享內存提供了較好的方法該緩沖區實際上是一個磁盤文件的內存映像二者的變化將保持同步即內存數據發生變化會立刻反映到磁盤文件中這樣會有效的保證共享內存的實現
  
  將共享內存和磁盤文件建立聯系的是文件通道類FileChannel該類的加入是JDK為了統一對外部設備(文件網絡接口等)的訪問方法並且加強了多線程對同一文件進行存取的安全性例如讀寫操作統一成read和write這裡只是用它來建立共享內存用它建立了共享內存和磁盤文件之間的一個通道
  
  打開一個文件建立一個文件通道可以用RandomAccessFile類中的方法getChannel該方法將直接返回一個文件通道該文件通道由於對應的文件設為隨機存取文件一方面可以進行讀寫兩種操作另一方面使用它不會破壞映像文件的內容(如果用FileOutputStream直接打開一個映像文件會將該文件的大小置為當然數據會全部丟失)這裡如果用 FileOutputStream和FileInputStream則不能理想的實現共享內存的要求因為這兩個類同時實現自由的讀寫操作要困難得多
  
  下面的代碼實現了如上功能它的作用類似UNIX系統中的mmap函數
  
  // 獲得一個只讀的隨機存取文件對象
  RandomAccessFile RAFile = new RandomAccessFile(filenamer);
  
  // 獲得相應的文件通道
  FileChannel fc = RAFilegetChannel();
  
  // 取得文件的實際大小以便映像到共享內存
  int size = (int)fcsize();
  
  // 獲得共享內存緩沖區該共享內存只讀
  MappedByteBuffer mapBuf = fcmap(FileChannelMAP_ROsize);
  
  // 獲得一個可讀寫的隨機存取文件對象
  RAFile = new RandomAccessFile(filenamerw);
  
  // 獲得相應的文件通道
  fc = RAFilegetChannel();
  
  // 取得文件的實際大小以便映像到共享內存
  size = (int)fcsize();
  
  // 獲得共享內存緩沖區該共享內存可讀寫
  mapBuf = fcmap(FileChannelMAP_RWsize);
  
  // 獲取頭部消息存取權限
  mode = mapBufgetInt();
  
  如果多個應用映像同一文件名的共享內存則意味著這多個應用共享了同一內存數據這些應用對於文件可以具有同等存取權限一個應用對數據的刷新會更新到多個應用中
  
  為了防止多個應用同時對共享內存進行寫操作可以在該共享內存的頭部信息加入寫操作標志該共享內存的頭部基本信息至少有
  
  int Length // 共享內存的長度
  int mode; // 該共享內存目前的存取模式
  
  
  
  
  
  共享內存的頭部信息是類的私有信息在多個應用可以對同一共享內存執行寫操作時開始執行寫操作和結束寫操作時需調用如下方法
  
  public boolean StartWrite()
  {
  if(mode == ) { // 標志為則表示可寫
  mode = ; // 置標志為意味著別的應用不可寫該共享內存
  mapBufflip();
  mapBufputInt(mode); // 寫如共享內存的頭部信息
  return true;
  }
  else {
  return false; // 指明已經有應用在寫該共享內存本應用不可寫該共享內存
  }
  }
  
  public boolean StopWrite()
  {
  mode = ; // 釋放寫權限
  mapBufflip();
  mapBufputInt(mode); // 寫入共享內存頭部信息
  return true;
  }
  
  
  這裡提供的類文件mmapjava封裝了共享內存的基本接口讀者可以用該類擴展成自己需要的功能全面的類
  
  
  如果執行寫操作的應用異常中止那麼映像文件的共享內存將不再能執行寫操作為了在應用異常中止後寫操作禁止標志自動消除必須讓運行的應用獲知退出的應用在多線程應用中可以用同步方法獲得這樣的效果但是在多進程中同步是不起作用的方法可以采用的多種技巧這裡只是描述一可能的實現采用文件鎖的方式寫共享內存應用在獲得對一個共享內存寫權限的時候除了判斷頭部信息的寫權限標志外還要判斷一個臨時的鎖文件是否可以得到如果可以得到則即使頭部信息的寫權限標志為(上述)也可以啟動寫權限其實這已經表明寫權限獲得的應用已經異常退出這段代碼如下
  
  // 打開一個臨時的文件注意同一共享內存該文件名要相同可以在共享文件名後加後綴lock
  RandomAccessFile fis = new RandomAccessFile(shmlockrw);
  // 獲得文件通道
  FileChannel lockfc = fisgetChannel();
  // 獲得文件的獨占鎖該方法不產生堵塞立刻返回
  FileLock flock = lockfctryLock();
  // 如果為空則表明已經有應用占有該鎖
  if(flock == null) {
  // 不能執行寫操作
  }
  else {
  // 可以執行寫操作
  }
  
  
  
  該鎖會在應用異常退出後自動釋放這正是該處所需要的方法
  
  
   共享內存在java中的應用
  共享內存在java應用中經常有如下兩種種應用
  
  永久對象配置
  在java服務器應用中用戶可能會在運行過程中配置一些參數而這些參數需要永久有效當服務器應用重新啟動後這些配置參數仍然可以對應用起作用這就可以用到該文中的共享內存該共享內存中保存了服務器的運行參數和一些對象運行特性可以在應用啟動時讀入以啟用以前配置的參數
  
  查詢共享數據
  一個應用(例 sysjava)是系統的服務進程其系統的運行狀態記錄在共享內存中其中運行狀態可能是不斷變化的為了隨時了解系統的運行狀態啟動另一個應用(例 monjava)該應用查詢該共享內存匯報系統的運行狀態
  
  可見共享內存在java應用中還是很有用的只要組織好共享內存的數據結構共享內存就可以在應用開發中發揮很不錯的作用
  
  
  

From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19194.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.