对UNIX系统来说,共享内存分为一般共享内存和映像文件共享内存两种,对windows实际上只有映像文件共享内存一种。所以java应用中也是只能创建映像文件共享内存。使用共享内存,有如下几个特点:
1、可以被多个进程打开访问。
2、读写操作的进程在执行读写操作时其他进程不能进行写操作。
3、多个进程可以交替对某一共享内存执行写操作。
4、一个进程执行了内存的写操作后,不影响其他进程对该内存的访问。同时其他进程对更新后的内存具有可见性。
5、在进程执行写操作时,如果异常退出,对其他进程写操作禁止应自动解除。
一般我们操作共享内存有以下几种情况,主要关注1,2:
1、独占的写操作,相应有独占的写操作等待队列。独占的写操作本身不会发生数据的一致性问题。
2、共享的写操作,相应有共享的写操作等待队列。共享的写操作哦则要注意防止发生数据的一致性问题。
3、独占的读操作,相应有共享的读操作等待队列。
4、共享的读操作,相应有共享的读操作等待队列。
在jdk1.4中提供的类MappedByteBuffer为我们提供了实现共享内存的方法,该缓冲区实际上是一个磁盘文件的内存映像。二者的变化保持同步,即内存数据发生变化会立刻反应到磁盘文件中,这样会有效的保证共享内存的实现。废话不多说,直接看代码:
package com.hx.sharemem; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.Properties; import com.hx.util.FileUtil; /** * 共享内存操作类 * @author hx * */ public class ShareMemory { int flen = 41779264; //开辟共享内存大小 int fsize = 0; //文件的实际大小 String shareFileName; //共享内存文件名 String sharePath; //共享内存路径 MappedByteBuffer mapBuf = null; //定义共享内存缓冲区 FileChannel fc = null; //定义相应的文件通道 FileLock fl = null; //定义文件区域锁定的标记。 Properties p = null; RandomAccessFile RAFile = null; //定义一个随机存取文件对象 /** * * @param sp 共享内存文件路径 * @param sf 共享内存文件名 */ public ShareMemory(String sp, String sf) { if (sp.length() != 0) { FileUtil.CreateDir(sp); this.sharePath = sp + File.separator; } else { this.sharePath = sp; } this.shareFileName = sf; try { // 获得一个只读的随机存取文件对象 "rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。 RAFile = new RandomAccessFile(this.sharePath + this.shareFileName + ".sm", "rw"); //获取相应的文件通道 fc = RAFile.getChannel(); //获取实际文件的大小 fsize = (int) fc.size(); if (fsize < flen) { byte bb[] = new byte[flen - fsize]; //创建字节缓冲区 ByteBuffer bf = ByteBuffer.wrap(bb); bf.clear(); //设置此通道的文件位置。 fc.position(fsize); //将字节序列从给定的缓冲区写入此通道。 fc.write(bf); fc.force(false); fsize = flen; } //将此通道的文件区域直接映射到内存中。 mapBuf = fc.map(FileChannel.MapMode.READ_WRITE, 0, fsize); } catch (IOException e) { e.printStackTrace(); } } /** * * @param ps 锁定区域开始的位置;必须为非负数 * @param len 锁定区域的大小;必须为非负数 * @param buff 写入的数据 * @return */ public synchronized int write(int ps, int len, byte[] buff) { if (ps >= fsize || ps + len >= fsize) { return 0; } //定义文件区域锁定的标记。 FileLock fl = null; try { //获取此通道的文件给定区域上的锁定。 fl = fc.lock(ps, len, false); if (fl != null) { mapBuf.position(ps); ByteBuffer bf1 = ByteBuffer.wrap(buff); mapBuf.put(bf1); //释放此锁定。 fl.release(); return len; } } catch (Exception e) { if (fl != null) { try { fl.release(); } catch (IOException e1) { System.out.println(e1.toString()); } } return 0; } return 0; } /** * * @param ps 锁定区域开始的位置;必须为非负数 * @param len 锁定区域的大小;必须为非负数 * @param buff 要取的数据 * @return */ public synchronized int read(int ps, int len, byte[] buff) { if (ps >= fsize) { return 0; } //定义文件区域锁定的标记。 FileLock fl = null; try { fl = fc.lock(ps, len, false); if (fl != null) { //System.out.println( "ps="+ps ); mapBuf.position(ps); if (mapBuf.remaining() < len) { len = mapBuf.remaining(); } if (len > 0) { mapBuf.get(buff, 0, len); } fl.release(); return len; } } catch (Exception e) { if (fl != null) { try { fl.release(); } catch (IOException e1) { System.out.println(e1.toString()); } } return 0; } return 0; } /** * 完成,关闭相关操作 */ protected void finalize() throws Throwable { if (fc != null) { try { fc.close(); } catch (IOException e) { System.out.println(e.toString()); } fc = null; } if (RAFile != null) { try { RAFile.close(); } catch (IOException e) { System.out.println(e.toString()); } RAFile = null; } mapBuf = null; } /** * 关闭共享内存操作 */ public synchronized void closeSMFile() { if (fc != null) { try { fc.close(); } catch (IOException e) { System.out.println(e.toString()); } fc = null; } if (RAFile != null) { try { RAFile.close(); } catch (IOException e) { System.out.println(e.toString()); } RAFile = null; } mapBuf = null; } /** * 检查退出 * @return true-成功,false-失败 */ public synchronized boolean checkToExit() { byte bb[] = new byte[1]; if (read(1, 1, bb) > 0) { if (bb[0] == 1) { return true; } } return false; } /** * 复位退出 */ public synchronized void resetExit() { byte bb[] = new byte[1]; bb[0] = 0; write(1, 1, bb); } /** * 退出 */ public synchronized void toExit() { byte bb[] = new byte[1]; bb[0] = 1; write(1, 1, bb); } public static void main(String arsg[]) throws Exception{ ShareMemory sm = new ShareMemory("E://demo","test"); String str = "中文测试"; sm.write(40, 20, str.getBytes("UTF-8")); byte[] b = new byte[20]; sm.read(40, 20, b); System.out.println(new String(b,"UTF-8")); } }