共享内存在Java中的实现和应用
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
共享内存在Java中的实现和应用
在java语言中,基本上没有提及共享内存这个概念,但是,在某一些应用中,共享内 存确实非常有用,例如采用java语言的分布式应用系统中,存在着大量的分布式共享对象, 很多时候需要查询这些对象的状态,以查看系统是否运行正常或者了解这些对象的目前的一 些统计数据和状态。如果采用网络通信的方式,显然会增加应用的额外负担,也增加了一些 不必要的应用编程。而如果采用共享内存的方式,则可以直接通过共享内存查看对象的状态 数据和统计数据,从而减少了一些不必要的麻烦。
共享内存对应应用开发的意义
对熟知UNIX系统应用开发的程序员来说,IPC(InterProcess Communication)机制是非常熟悉的,IPC基本包括共享内存、信号灯操作、消息队列、信号处理等部分,是开发应用中非常重要的必不可少的工具。其中共享内存IPC机制的关键,对于数据共享、系统快速查询、动态配置、减少资源耗费等均有独到的优点。
对应UNIX系统来说,共享内存分为一般共享内存和映像文件共享内存两种,而对应 Windows,实际上只有映像文件共享内存一种。所以java应用中也是只能创建映像文件共享内存。
在java语言中,基本上没有提及共享内存这个概念,但是,在某一些应用中,共享内存确实非常有用,例如采用java语言的分布式应用系统中,存在着大量的分布式共享对象,很多时候需要查询这些对象的状态,以查看系统是否运行正常或者了解这些对象的目前的一些统计数据和状态。如果采用网络通信的方式,显然会增加应用的额外负担,也增加了一些不必要的应用编程。而如果采用共享内存的方式,则可以直接通过共享内存查看对象的状态数据和统计数据,从而减少了一些不必要的麻烦。
共享内存的使用有如下几个特点:
可以被多个进程打开访问;
读写操作的进程在执行读写操作时其他进程不能进行写操作;
多个进程可以交替对某一共享内存执行写操作;
一个进程执行了内存的写操作后,不影响其他进程对该内存的访问。同时其他进程对更新后的内存具有可见性。
在进程执行写操作时如果异常退出,对其他进程写操作禁止应自动解除。
相对共享文件,数据访问的方便性和效率有
另外,共享内存的使用上有如下情况:
独占的写操作,相应有独占的写操作等待队列。独占的写操作本身不会发生数据的一致性问题。
共享的写操作,相应有共享的写操作等待队列。共享的写操作则要注意防止发生数据的一致性问题。
独占的读操作,相应有共享的读操作等待队列;
共享的读操作,相应有共享的读操作等待队列。
一般情况下,我们只是关心第一二种情况。
共享内存在java中的实现
在jdk1.4中提供的类MappedB y teBu ff er为我们实现共享内存提供了较好的方法。该缓冲区实际上是一个磁盘文件的内存映像。二者的变化将保持同步,即内存数据发生变化会立刻反映到磁盘文件中,这样会有效的保证共享内存的实现。
将共享内存和磁盘文件建立联系的是文件通道类:F i l eC h anne l。该类的加入是J DK为了统一对外部设备(文件、网络接口等)的访问方法,并且加强了多线程对同一文件进行存取的安全性。例如读写操作统一成read和write。这里只是用它来建立共享内存用,它建立了共享内存和磁盘文件之间的一个通道。
打开一个文件建立一个文件通道可以用R andom A ccess F i l e类中的方法g etC h anne l。该方法将直接返回一个文件通道。该文件通道由于对应的文件设为随机存取文件,一方面可以进行读写两种操作,另一方面使用它不会破坏映像文件的内容(如果用F i l e O utput S tream直接打开一个映像文件会将该文件的大小置为0,当然数据会全部丢失)。这里,如果用 F i l e O utput S tream和F i l eInput S tream则不能理想的实现共享内存的要求,因为这两个类同时实现自由的读写操作要困难得多。
下面的代码实现了如上功能,它的作用类似UNIX系统中的mmap函数。
//获得一个只读的随机存取文件对象
R andom A ccess F i l e RAF i l e = new R andom A ccess F i l e(f i l ename,"r");
//获得相应的文件通道
F i l eC h anne l f c =RAF i l e.g etC h anne l();
//取得文件的实际大小,以便映像到共享内存
int si z e =(int)f c.si z e();
//获得共享内存缓冲区,该共享内存只读
MappedB y teBu ff er mapBu f=f c.map(F i l eC h anne l.M A P_RO,0,si z e);
//获得一个可读写的随机存取文件对象
RAF i l e = new R andom A ccess F i l e(f i l ename,"rw");
//获得相应的文件通道
f c =RAF i l e.
g etC
h anne l();
//取得文件的实际大小,以便映像到共享内存
si z e =(int)f c.si z e();
//获得共享内存缓冲区,该共享内存可读写
mapBu f=f c.map(F i l eC h anne l.M A P_R W,0,si z e);
//获取头部消息:存取权限
mode = mapBu f.g etInt();
如果多个应用映像同一文件名的共享内存,则意味着这多个应用共享了同一内存数据。这些应用对于文件可以具有同等存取权限,一个应用对数据的刷新会更新到多个应用中。
为了防止多个应用同时对共享内存进行写操作,可以在该共享内存的头部信息加入写操作标志。该共享内存的头部基本信息至少有:
int L en g t h; // 共享内存的长度。
int mode;// 该共享内存目前的存取模式。
共享内存的头部信息是类的私有信息,在多个应用可以对同一共享内存执行写操作时,开始执行写操作和结束写操作时,需调用如下方法:
pu bl ic b oo l ean S tartWrite()
{
i f(mode ==0){//标志为0,则表示可写