1 共享内存对应应用开发
![](/icons/92657de.gif)
意义
JAVA中文站社区门户$Ft2dSB2]2}5H#T对熟知UNIX系统应用开发
![](/icons/92657de.gif)
![](/icons/92657chengxu.gif)
员来说
![](/icons/92657dou.gif)
IPC(InterProcess Communication)机制是非常熟悉
![](/icons/92657de.gif)
![](/icons/92657dou.gif)
IPC基本包括共享内存、信号灯操作、消息队列、信号处理等部分
![](/icons/92657dou.gif)
是开发应用中非常重要
![](/icons/92657de.gif)
必不可少
![](/icons/92657de.gif)
工具
![](/icons/92657dou2.gif)
其中共享内存IPC机制
![](/icons/92657de.gif)
关键
![](/icons/92657dou.gif)
对于数据共享、系统快速查询、动态配置、减少资源耗费等均有独到
![](/icons/92657de.gif)
优点
JAVA中文站社区门户d#k:`/X8x%nk-iJAVA中文站社区门户"d*v9|1p:rZ对应UNIX系统来说
![](/icons/92657dou.gif)
共享内存分为
![](/icons/92657yi.gif)
般共享内存和映像文件共享内存两种
![](/icons/92657dou.gif)
而对应 Windows
![](/icons/92657dou.gif)
实际上只有映像文件共享内存
![](/icons/92657yi.gif)
种
![](/icons/92657dou2.gif)
所以java应用中也是只能创建映像文件共享内存
JAVA中文站社区门户BLEY ~*LnJAVA中文站社区门户E0H7R9yP w m在java语言中
![](/icons/92657dou.gif)
基本上没有提及共享内存这个概念
![](/icons/92657dou.gif)
但是
![](/icons/92657dou.gif)
在某
![](/icons/92657yi.gif)
些应用中
![](/icons/92657dou.gif)
共享内存确实非常有用
![](/icons/92657dou.gif)
例如采用java语言
![](/icons/92657de.gif)
分布式应用系统中
![](/icons/92657dou.gif)
存在着大量
![](/icons/92657de.gif)
分布式共享对象
![](/icons/92657dou.gif)
很多时候需要查询这些对象
![](/icons/92657de.gif)
状态
![](/icons/92657dou.gif)
以查看系统是否运行正常或者了解这些对象
![](/icons/92657de.gif)
目前
![](/icons/92657de.gif)
![](/icons/92657yi.gif)
些统计数据和状态
![](/icons/92657dou2.gif)
如果采用网络通信
![](/icons/92657de.gif)
方式
![](/icons/92657dou.gif)
显然会增加应用
![](/icons/92657de.gif)
额外负担
![](/icons/92657dou.gif)
也增加了
![](/icons/92657yi.gif)
些不必要
![](/icons/92657de.gif)
应用编程
![](/icons/92657dou2.gif)
而如果采用共享内存
![](/icons/92657de.gif)
方式
![](/icons/92657dou.gif)
则可以直接通过共享内存查看对象
![](/icons/92657de.gif)
状态数据和统计数据
![](/icons/92657dou.gif)
从而减少了
![](/icons/92657yi.gif)
些不必要
![](/icons/92657de.gif)
麻烦
V
i jlfY8wf1~9J_'X!DA~lQ*V&?$l`共享内存
![](/icons/92657de.gif)
使用有如下几个特点:
(]+H b$aMT"c%Vw[7uJAVA中文站社区门户{oD5n2mor可以被多个进程打开访问;
,z9r#n j2YbU读写操作
![](/icons/92657de.gif)
进程在执行读写操作时其他进程不能进行写操作;
JAVA中文站社区门户^(]
u Gc]0Q多个进程可以交替对某
![](/icons/92657yi.gif)
共享内存执行写操作;
JAVA中文站社区门户kdy%]S0@K(V`!v2J(S![](/icons/92657yi.gif)
个进程执行了内存
![](/icons/92657de.gif)
写操作后
![](/icons/92657dou.gif)
不影响其他进程对该内存
![](/icons/92657de.gif)
访问
![](/icons/92657dou2.gif)
同时其他进程对更新后
![](/icons/92657de.gif)
内存具有可见性
'v9l|R2Bg在进程执行写操作时如果异常退出
![](/icons/92657dou.gif)
对其他进程写操作禁止应自动解除
JAVA中文站社区门户v5m1jk~相对共享文件
![](/icons/92657dou.gif)
数据访问
![](/icons/92657de.gif)
方便性和效率有
zC6]
?+BVd(w3NH3wgT%N\li9TmP }JAVA中文站社区门户:UVp(vDto\
F C]:P'p)n2v另外
![](/icons/92657dou.gif)
共享内存
![](/icons/92657de.gif)
使用上有如下情况:
^aB"qt$z$]Fy-]
a GBR`n)l独占
![](/icons/92657de.gif)
写操作
![](/icons/92657dou.gif)
相应有独占
![](/icons/92657de.gif)
写操作等待队列
![](/icons/92657dou2.gif)
独占
![](/icons/92657de.gif)
写操作本身不会发生数据
![](/icons/92657de.gif)
![](/icons/92657yi.gif)
致性问题
JAVA中文站社区门户A,Aadq@o:`:e4f|共享
![](/icons/92657de.gif)
写操作
![](/icons/92657dou.gif)
相应有共享
![](/icons/92657de.gif)
写操作等待队列
![](/icons/92657dou2.gif)
共享
![](/icons/92657de.gif)
写操作则要注意防止发生数据
![](/icons/92657de.gif)
![](/icons/92657yi.gif)
致性问题
JAVA中文站社区门户4i,cU%ns"O独占
![](/icons/92657de.gif)
读操作
![](/icons/92657dou.gif)
相应有共享
![](/icons/92657de.gif)
读操作等待队列;
JAVA中文站社区门户:`*V,h9u&g(W+_共享
![](/icons/92657de.gif)
读操作
![](/icons/92657dou.gif)
相应有共享
![](/icons/92657de.gif)
读操作等待队列
JAVA中文站社区门户[3__3@ [8[JAVA中文站社区门户 {
g&m_3q/G_6r
Zd'^+z"t1O9gR4Kpf8{_*bP![](/icons/92657yi.gif)
般情况下
![](/icons/92657dou.gif)
我们只是关心第
![](/icons/92657yi.gif)
2种情况
JAVA中文站社区门户lL0_7PVjC&P+j@2{5p \
c2 共享内存在java中
![](/icons/92657de.gif)
实现
8A4o in9b:@
R'm*T Sqk在jdk1.4中提供
![](/icons/92657de.gif)
类MappedByteBuffer为我们实现共享内存提供了较好
![](/icons/92657de.gif)
思路方法
![](/icons/92657dou2.gif)
该缓冲区实际上是
![](/icons/92657yi.gif)
个磁盘文件
![](/icons/92657de.gif)
内存映像
![](/icons/92657dou2.gif)
2者
![](/icons/92657de.gif)
变化将保持同步
![](/icons/92657dou.gif)
即内存数据发生变化会立刻反映到磁盘文件中
![](/icons/92657dou.gif)
这样会有效
![](/icons/92657de.gif)
保证共享内存
![](/icons/92657de.gif)
实现
aU4q0u+yv&GH!SKl.t)^Ig将共享内存和磁盘文件建立联系
![](/icons/92657de.gif)
是文件通道类:FileChannel
![](/icons/92657dou2.gif)
该类
![](/icons/92657de.gif)
加入是JDK为了统
![](/icons/92657yi.gif)
对外部设备(文件、网络接口等)
![](/icons/92657de.gif)
访问思路方法
![](/icons/92657dou.gif)
并且加强了多线程对同
![](/icons/92657yi.gif)
文件进行存取
![](/icons/92657de.gif)
安全性
![](/icons/92657dou2.gif)
例如读写操作统
![](/icons/92657yi.gif)
成read和write
![](/icons/92657dou2.gif)
这里只是用它来建立共享内存用
![](/icons/92657dou.gif)
它建立了共享内存和磁盘文件的间
![](/icons/92657de.gif)
![](/icons/92657yi.gif)
个通道
\anIj
V0fa?.s f`0d_ _R9|-h(XZ f打开
![](/icons/92657yi.gif)
个文件建立
![](/icons/92657yi.gif)
个文件通道可以用RandomAccessFile类中
![](/icons/92657de.gif)
思路方法getChannel
![](/icons/92657dou2.gif)
该思路方法将直接返回
![](/icons/92657yi.gif)
个文件通道
![](/icons/92657dou2.gif)
该文件通道由于对应
![](/icons/92657de.gif)
文件设为随机存取文件
![](/icons/92657dou.gif)
![](/icons/92657yi.gif)
方面可以进行读写两种操作
![](/icons/92657dou.gif)
另
![](/icons/92657yi.gif)
方面使用它不会破坏映像文件
![](/icons/92657de.gif)
内容(如果用FileOutputStream直接打开
![](/icons/92657yi.gif)
个映像文件会将该文件
![](/icons/92657de.gif)
大小置为0
![](/icons/92657dou.gif)
当然数据会全部丢失)
![](/icons/92657dou2.gif)
这里
![](/icons/92657dou.gif)
如果用 FileOutputStream和FileInputStream则不能理想
![](/icons/92657de.gif)
实现共享内存
![](/icons/92657de.gif)
要求
![](/icons/92657dou.gif)
![](/icons/92657yinwei.gif)
这两个类同时实现自由
![](/icons/92657de.gif)
读写操作要困难得多
JAVA中文站社区门户(TN`_8i0R+au/Z?$i#y.D~'_d下面
![](/icons/92657de.gif)
代码实现了如上功能
![](/icons/92657dou.gif)
它
![](/icons/92657de.gif)
作用类似UNIX系统中
![](/icons/92657de.gif)
mmap
![](/icons/92657hanshu.gif)
JAVA中文站社区门户0lC
Ig,\6fJAVA中文站社区门户u*g,VzQ)gT// 获得
![](/icons/92657yi.gif)
个只读
![](/icons/92657de.gif)
随机存取文件对象
4s-bT/~&j3K wRandomAccessFile RAFile =
![](/icons/92657new.gif)
RandomAccessFile(filename,"r");
x.ox1a{0fh D5} o;J+{W$I/{3gE j// 获得相应
![](/icons/92657de.gif)
文件通道
JAVA中文站社区门户
S1q9|sd~OFileChannel fc = RAFile.getChannel
![](/icons/92657kh.gif)
;
JAVA中文站社区门户.d
I j(d7s
ZU t7j8d
{0i
u IH `// 取得文件
![](/icons/92657de.gif)
实际大小
![](/icons/92657dou.gif)
以便映像到共享内存
nKj,_r![](/icons/92657int.gif)
size = (
![](/icons/92657int.gif)
)fc.size
![](/icons/92657kh.gif)
;
^^G'i&^-VJAVA中文站社区门户nW;e/@.x,y// 获得共享内存缓冲区
![](/icons/92657dou.gif)
该共享内存只读
:m0y&]
~7`DxZ~MappedByteBuffer mapBuf = fc.map(FileChannel.MAP_RO,0,size);
8f%IAN:G$[%OjiT-ArF{~T// 获得
![](/icons/92657yi.gif)
个可读写
![](/icons/92657de.gif)
随机存取文件对象
JAVA中文站社区门户
YjtReY-gD*d!x^RAFile =
![](/icons/92657new.gif)
RandomAccessFile(filename,"rw");
JAVA中文站社区门户LDvP9tFTfhvPP5h,@r8T// 获得相应
![](/icons/92657de.gif)
文件通道
#k%T3m/f'r]fc = RAFile.getChannel
![](/icons/92657kh.gif)
;
JAVA中文站社区门户!K
q`)\3J6Es}JAVA中文站社区门户C/gXB6q,_!|u// 取得文件
![](/icons/92657de.gif)
实际大小
![](/icons/92657dou.gif)
以便映像到共享内存
AVQ|1~Psize = (
![](/icons/92657int.gif)
)fc.size
![](/icons/92657kh.gif)
;
JAVA中文站社区门户Z@])l@7x,W
DIt(gF// 获得共享内存缓冲区
![](/icons/92657dou.gif)
该共享内存可读写
JAVA中文站社区门户0\8ym!s2q/Y~(VmapBuf = fc.map(FileChannel.MAP_RW,0,size);
JAVA中文站社区门户V}!D"Mt^6W_dpp5c
l// 获取头部消息:存取权限
|m|'C%N uY0]#Gmode = mapBuf.getInt
![](/icons/92657kh.gif)
;
N%R!{
j8~9]+u;e
Z}0wJAVA中文站社区门户1o3U1p6n js1RrR如果多个应用映像同
![](/icons/92657yi.gif)
文件名
![](/icons/92657de.gif)
共享内存
![](/icons/92657dou.gif)
则意味着这多个应用共享了同
![](/icons/92657yi.gif)
内存数据
![](/icons/92657dou2.gif)
这些应用对于文件可以具有同等存取权限
![](/icons/92657dou.gif)
![](/icons/92657yi.gif)
个应用对数据
![](/icons/92657de.gif)
刷新会更新到多个应用中
JAVA中文站社区门户c7^b1\1f[JAVA中文站社区门户9Igq l%o为了防止多个应用同时对共享内存进行写操作
![](/icons/92657dou.gif)
可以在该共享内存
![](/icons/92657de.gif)
头部信息加入写操作标志
![](/icons/92657dou2.gif)
该共享内存
![](/icons/92657de.gif)
头部基本信息至少有:
*mP7Na-KCkJAVA中文站社区门户0r@ sO4K&\![](/icons/92657int.gif)
Length; // 共享内存
![](/icons/92657de.gif)
长度
,[3Q
|3Du![](/icons/92657int.gif)
mode; // 该共享内存目前
![](/icons/92657de.gif)
存取模式
0hv8i9k)C.e/VJAVA中文站社区门户qP0A,a9g ?Z1g$|/d
A+_JAVA中文站社区门户{b[cPR1I`2X|@JAVA中文站社区门户 W*Li;e|\5F;Vp7EQfv\OJX3f(G7T共享内存
![](/icons/92657de.gif)
头部信息是类
![](/icons/92657de.gif)
私有信息
![](/icons/92657dou.gif)
在多个应用可以对同
![](/icons/92657yi.gif)
共享内存执行写操作时
![](/icons/92657dou.gif)
开始执行写操作和结束写操作时
![](/icons/92657dou.gif)
需
![](/icons/92657diaoyong.gif)
如下思路方法:
JAVA中文站社区门户7Uoc`.k%I.@aJAVA中文站社区门户 p6th j-wci,V$]tOpublic boolean StartWrite
JAVA中文站社区门户,kF:N2~]{
~+Z)@5]`(i d[C![](/icons/92657if.gif)
(mode
![](/icons/92657dd.gif)
0) { // 标志为0
![](/icons/92657dou.gif)
则表示可写
S7PEzd9QtLmode = 1; // 置标志为1
![](/icons/92657dou.gif)
意味着别
![](/icons/92657de.gif)
应用不可写该共享内存
m\}2GHQ*hAjS&x-B\mapBuf.flip
![](/icons/92657kh.gif)
;
JAVA中文站社区门户2b|WG*ngmapBuf.putInt(mode); // 写如共享内存
![](/icons/92657de.gif)
头部信息
JAVA中文站社区门户 it7z_7vS,zV![](/icons/92657return.gif)
true;
JAVA中文站社区门户:{}"n [Qj]}
JAVA中文站社区门户hvH:Zl;F
qGc
V4v![](/icons/92657else.gif)
{
JAVA中文站社区门户S0L'^_h!{Vx
L![](/icons/92657return.gif)
false; // 指明已经有应用在写该共享内存
![](/icons/92657dou.gif)
本应用不可写该共享内存
4|A4bQt
D"Z^Q}
I8R)q$a(?]a,X}
KA+Z7Je ^/yq}JBLpublic boolean StopWrite
JAVA中文站社区门户
G _7V K1Q,D{
X#yc!_.y"|1D"imode = 0; // 释放写权限
JAVA中文站社区门户s^v,D fG)i.aL?bmapBuf.flip
![](/icons/92657kh.gif)
;
JAVA中文站社区门户 g faQYXx$|(o#}mapBuf.putInt(mode); // 写入共享内存头部信息
hK(|A nR
E![](/icons/92657return.gif)
true;
E5o*y4]b;N)r}
.a&Lb4{M\'L|:n*]5}mJAVA中文站社区门户@ t
g7Jm7x\这里提供
![](/icons/92657de.gif)
类文件mmap.java封装了共享内存
![](/icons/92657de.gif)
基本接口
![](/icons/92657dou.gif)
读者可以用该类扩展成自己需要
![](/icons/92657de.gif)
功能全面
![](/icons/92657de.gif)
类
JAVA中文站社区门户-`In Kt
jp0~*Ri,d.jfyyJAVA中文站社区门户/i jo4}J"W/S8T!A4{,[C如果执行写操作
![](/icons/92657de.gif)
应用异常中止
![](/icons/92657dou.gif)
那么映像文件
![](/icons/92657de.gif)
共享内存将不再能执行写操作
![](/icons/92657dou2.gif)
为了在应用异常中止后
![](/icons/92657dou.gif)
写操作禁止标志自动消除
![](/icons/92657dou.gif)
必须让运行
![](/icons/92657de.gif)
应用获知退出
![](/icons/92657de.gif)
应用
![](/icons/92657dou2.gif)
在多线程应用中
![](/icons/92657dou.gif)
可以用同步思路方法获得这样
![](/icons/92657de.gif)
效果
![](/icons/92657dou.gif)
但是在多进程中
![](/icons/92657dou.gif)
同步是不起作用
![](/icons/92657de.gif)
![](/icons/92657dou2.gif)
思路方法可以采用
![](/icons/92657de.gif)
多种窍门技巧
![](/icons/92657dou.gif)
这里只是描述
![](/icons/92657yi.gif)
可能
![](/icons/92657de.gif)
实现:采用文件锁
![](/icons/92657de.gif)
方式
![](/icons/92657dou2.gif)
写共享内存应用在获得对
![](/icons/92657yi.gif)
个共享内存写权限
![](/icons/92657de.gif)
时候
![](/icons/92657dou.gif)
除了判断头部信息
![](/icons/92657de.gif)
写权限标志外
![](/icons/92657dou.gif)
还要判断
![](/icons/92657yi.gif)
个临时
![](/icons/92657de.gif)
锁文件是否可以得到
![](/icons/92657dou.gif)
如果可以得到
![](/icons/92657dou.gif)
则即使头部信息
![](/icons/92657de.gif)
写权限标志为1(上述)
![](/icons/92657dou.gif)
也可以启动写权限
![](/icons/92657dou.gif)
其实这已经表明写权限获得
![](/icons/92657de.gif)
应用已经异常退出
![](/icons/92657dou.gif)
这段代码如下:
JAVA中文站社区门户!F[3LE'gUa-EJAVA中文站社区门户l@7?3Z5Sb$m:z(@// 打开
![](/icons/92657yi.gif)
个临时
![](/icons/92657de.gif)
文件
![](/icons/92657dou.gif)
注意同
![](/icons/92657yi.gif)
共享内存
![](/icons/92657dou.gif)
该文件名要相同
![](/icons/92657dou.gif)
可以在共享文件名后加后缀“.lock”
JAVA中文站社区门户rD_9a+`Y*R#FoRandomAccessFile fis =
![](/icons/92657new.gif)
RandomAccessFile("shm.lock","rw");
JAVA中文站社区门户ktsTG(p&`p.X// 获得文件通道
.U
lhSOM8FHo&H^FileChannel lockfc = fis.getChannel
![](/icons/92657kh.gif)
;
JAVA中文站社区门户w$Q.jV5X:zB// 获得文件
![](/icons/92657de.gif)
独占锁
![](/icons/92657dou.gif)
该思路方法不产生堵塞
![](/icons/92657dou.gif)
立刻返回
\1}f#ZABxiFileLock flock = lockfc.tryLock
![](/icons/92657kh.gif)
;
JAVA中文站社区门户e-}wi5?y-c B
U0f// 如果为空
![](/icons/92657dou.gif)
则表明已经有应用占有该锁
JAVA中文站社区门户2Qm
{dK|4UMW#O[,m![](/icons/92657if.gif)
(flock
![](/icons/92657dd.gif)
null) {
F;Kq2h;Ec~rT...// 不能执行写操作
'Iq_s-v(OdtA}
JAVA中文站社区门户:@m^2\kB![](/icons/92657else.gif)
{
,zG&N~
|Ne']8e...// 可以执行写操作
JAVA中文站社区门户$b,HA
y;p
D9q+d}
JAVA中文站社区门户$J3EV0Xm pJAVA中文站社区门户`6o Z@ck#CJAVA中文站社区门户/n;[+e"lwJAVA中文站社区门户I{2q D
z5Lie该锁会在应用异常退出后自动释放
![](/icons/92657dou.gif)
这正是该处所需要
![](/icons/92657de.gif)
思路方法
9qEwN~B0E+R~9UDJAVA中文站社区门户qMS7I8{&z!Y6_JAVA中文站社区门户4i#kn1r;E\L
D I3 共享内存在java中
![](/icons/92657de.gif)
应用
JAVA中文站社区门户c7}Y,Q`*W(bp共享内存在java应用中
![](/icons/92657dou.gif)
经常有如下两种种应用:
JAVA中文站社区门户]m(S.HsJAVA中文站社区门户 I$Fu#a,rZ永久对象配置
JAVA中文站社区门户XV(l\4U8g9a在java服务器应用中
![](/icons/92657dou.gif)
用户可能会在运行过程中配置
![](/icons/92657yi.gif)
些参数
![](/icons/92657dou.gif)
而这些参数需要永久有效
![](/icons/92657dou.gif)
当服务器应用重新启动后
![](/icons/92657dou.gif)
这些配置参数仍然可以对应用起作用
![](/icons/92657dou2.gif)
这就可以用到该文中
![](/icons/92657de.gif)
共享内存
![](/icons/92657dou2.gif)
该共享内存中保存了服务器
![](/icons/92657de.gif)
运行参数和
![](/icons/92657yi.gif)
些对象运行特性
![](/icons/92657dou2.gif)
可以在应用启动时读入以启用以前配置
![](/icons/92657de.gif)
参数
JAVA中文站社区门户k#E
D8^:?4W0w%Cu
dJAVA中文站社区门户9BX{-K5]3Tz查询共享数据
+o6k En'H+i![](/icons/92657yi.gif)
个应用(例 sys.java)是系统
![](/icons/92657de.gif)
服务进程
![](/icons/92657dou.gif)
其系统
![](/icons/92657de.gif)
运行状态记录在共享内存中
![](/icons/92657dou.gif)
其中运行状态可能是不断变化
![](/icons/92657de.gif)
![](/icons/92657dou2.gif)
为了随时了解系统
![](/icons/92657de.gif)
运行状态
![](/icons/92657dou.gif)
启动另
![](/icons/92657yi.gif)
个应用(例 mon.java)
![](/icons/92657dou.gif)
该应用查询该共享内存
![](/icons/92657dou.gif)
汇报系统
![](/icons/92657de.gif)
运行状态
JAVA中文站社区门户7I9PKV:|JAVA中文站社区门户LkB7tVesP@!F可见
![](/icons/92657dou.gif)
共享内存在java应用中还是很有用
![](/icons/92657de.gif)
![](/icons/92657dou.gif)
只要组织好共享内存
![](/icons/92657de.gif)
数据结构
![](/icons/92657dou.gif)
共享内存就可以在应用开发中发挥很不错
![](/icons/92657de.gif)
作用
JAVA中文站社区门户G~3G@.VJAVA中文站社区门户o(E*](r;c8q,~4VOh有关作者
JAVA中文站社区门户t#hLs6]WU郭洪锋
![](/icons/92657dou.gif)
从事UNIX系统上
![](/icons/92657de.gif)
分布式应用系统开发
![](/icons/92657dou.gif)
已有 4年分布式应用系统开发经验
![](/icons/92657dou2.gif)
E-mail:
[email protected]
TAG:
Java
JAVA
java
应用