Java NIO 应用 -- 使用内存映射文件实现进程间通信
来源:互联网 发布:宁波地区房产成交数据 编辑:程序博客网 时间:2024/05/21 14:48
一看到 Java NIO 的内存映射文件(MappedByteBuffer),让我立即就联想到 Windows 系统的内存映射文件。Windows 系统的内存映射文件能用来在多个进程间共享数据,即进程间的共享内存,是通过把同一块内存区域映射到不同进程的地址空间中,从而达到共享内存。
Java NIO 的内存映射文件和 Windows 系统下的一样,都能把物理文件的内容映射到内存中,那么 MappedByteBuffer 是否能用来在不同 Java 进程(JVM) 间共享数据呢?答案是肯定的,这样在通常的 Socket 方式来实现 Java 进程间通信之上又多了一种方法。
在 Windows 中内存映射文件可以是脱离物理文件而存在的一块命名的内存区域,使用相同的内存映射名就能在不同的进程中共享同一片内存。然后,Java 的 MappedByteBuffer 总是与某个物理文件相关的,因为不管你是从 FileInputStream、FileOutputStream 还是 RandomAccessFile 得来的 FileChannel,再 map() 得到的内存映射文件 MappedByteBuffer,如果在构造 FileInputStream、FileOutputStream、RandomAccessFile 对象时不指定物理文件便会有 FileNotFoundException 异常。
所以 Java NIO 来实现共享内存的办法就是让不同进程的内存映射文件关联到同一个物理文件,因为 MappedByteBuffer 能让内存与文件即时的同步内容。严格说来,称之为内存共享是不准确的,其实就是两个 Java 进程通过中间文件来交换数据,用中间文件使得两个进程的两块内存区域的内容得到及时的同步。
用图来理解 Java NIO 的“共享内存”的实现原理:
知道了实现原理之后,下面用代码来演示两个进程间用内存映射文件来进行数据通信。代码 WriteShareMemory.java 往映射文件中依次写入 A、B、C ... Z,ReadShareMemory.java 逐个读出来,打印到屏幕上。代码对交换文件 swap.mm 的第一个字节作了读写标志,分别是 0-可读,1-正在写,2-可读。RandomAccessFile 得到的 Channel 能够灵活的进行读或写,并且不会破坏原有文件内容,而 FileInputStream 或 FileOutputStream 取得的 Channel 则很难达到这一功效,所以使用了 RandomAccessFile 来获得 FileChannel。
WriteShareMemory.java
01.
package
com.unmi;
02.
03.
import
java.io.RandomAccessFile;
04.
import
java.nio.MappedByteBuffer;
05.
import
java.nio.channels.FileChannel;
06.
import
java.nio.channels.FileChannel.MapMode;
07.
08.
/**
09.
* 往 "共享内存" 写入数据
10.
* @author Unmi
11.
*/
12.
public
class
WriteShareMemory {
13.
14.
/**
15.
* @param args
16.
* @throws Exception
17.
*/
18.
public
static
void
main(String[] args)
throws
Exception {
19.
RandomAccessFile raf =
new
RandomAccessFile(
"c:/swap.mm"
,
"rw"
);
20.
FileChannel fc = raf.getChannel();
21.
MappedByteBuffer mbb = fc.map(MapMode.READ_WRITE,
0
,
1024
);
22.
23.
//清除文件内容
24.
for
(
int
i=
0
;i<
1024
;i++){
25.
mbb.put(i,(
byte
)
0
);
26.
}
27.
28.
//从文件的第二个字节开始,依次写入 A-Z 字母,第一个字节指明了当前操作的位置
29.
for
(
int
i=
65
;i<
91
;i++){
30.
int
index = i-
63
;
31.
int
flag = mbb.get(
0
);
//可读标置第一个字节为 0
32.
if
(flag !=
0
){
//不是可写标示 0,则重复循环,等待
33.
i --;
34.
continue
;
35.
}
36.
mbb.put(
0
,(
byte
)
1
);
//正在写数据,标志第一个字节为 1
37.
mbb.put(
1
,(
byte
)(index));
//写数据的位置
38.
39.
System.out.println(
"程序 WriteShareMemory:"
+System.currentTimeMillis() +
40.
":位置:"
+ index +
" 写入数据:"
+ (
char
)i);
41.
42.
mbb.put(index,(
byte
)i);
//index 位置写入数据
43.
mbb.put(
0
,(
byte
)
2
);
//置可读数据标志第一个字节为 2
44.
Thread.sleep(
513
);
45.
}
46.
}
47.
}
ReadShareMemory.java
01.
package
com.unmi;
02.
03.
import
java.io.RandomAccessFile;
04.
import
java.nio.MappedByteBuffer;
05.
import
java.nio.channels.FileChannel;
06.
import
java.nio.channels.FileChannel.MapMode;
07.
08.
/**
09.
* 从 "共享内存" 读出数据
10.
* @author Unmi
11.
*/
12.
public
class
ReadShareMemory {
13.
14.
/**
15.
* @param args
16.
* @throws Exception
17.
*/
18.
public
static
void
main(String[] args)
throws
Exception {
19.
RandomAccessFile raf =
new
RandomAccessFile(
"c:/swap.mm"
,
"rw"
);
20.
FileChannel fc = raf.getChannel();
21.
MappedByteBuffer mbb = fc.map(MapMode.READ_WRITE,
0
,
1024
);
22.
int
lastIndex =
0
;
23.
24.
for
(
int
i=
1
;i<
27
;i++){
25.
int
flag = mbb.get(
0
);
//取读写数据的标志
26.
int
index = mbb.get(
1
);
//读取数据的位置,2 为可读
27.
28.
if
(flag !=
2
|| index == lastIndex){
//假如不可读,或未写入新数据时重复循环
29.
i--;
30.
continue
;
31.
}
32.
33.
lastIndex = index;
34.
System.out.println(
"程序 ReadShareMemory:"
+ System.currentTimeMillis() +
35.
":位置:"
+ index +
" 读出数据:"
+ (
char
)mbb.get(index));
36.
37.
mbb.put(
0
,(
byte
)
0
);
//置第一个字节为可读标志为 0
38.
39.
if
(index ==
27
){
//读完数据后退出
40.
break
;
41.
}
42.
}
43.
}
44.
}
在 Eclipse 中运行 WriteShareMemory,然后到命令行下运行 ReadShareMemory,你将会看到 WriteShareMemory 写一个字符,ReadShareMemory 读一个。
代码中使用了读写标志位,和写入的索引位置,所以在 WriteShareMemory 写入一个字符后,只有等待 ReadShareMemory 读出刚写入的字符后才会写入第二个字符。实际应用中可以加入更好的通知方式,如文件锁等。
你也可以查看执行时 c:/swap.mm 文件的内容来验证这一过程,因为 MappedByteBuffer 在运行时是一种 DirectByteBuffer,所以它能与文件即时的同步内容,无须通过 FileChannel 来 write(buffer) 往文件中手工写入数据,或 read(buffer) 手工读数据到内存中。
参考:1. 共享内存在Java中实现和应用
http://www.blogjava.net/Unmi/archive/2010/03/19/315940.html
- java nio 使用内存映射文件实现进程间通信
- Java NIO 应用 -- 使用内存映射文件实现进程间通信
- Java NIO 内存映射文件实现进程间通信
- Java NIO 内存映射文件实现进程间通信
- 内存映射文件实现多进程通信
- 内存映射文件实现多进程通信
- Windows进程通信--使用内存映射文件
- 用内存映射文件实现进程间通信
- 内存文件映射 进程间通信
- 内存文件映射-进程间通信
- 进程间通信 - 内存映射文件
- 内存文件映射-进程间通信
- 使用文件映射实现进程通信
- 通过内存映射实现进程间通信
- 利用内存映射实现进程间通信
- 内存映射实现进程间通信
- java nio 内存映射文件
- Java NIO 内存映射文件
- 呵呵
- cobertura report中的中文字符乱码问题
- gdb : C语言调试工具简单应用
- 命令行方式使用cobertura
- SSH配置方法
- Java NIO 应用 -- 使用内存映射文件实现进程间通信
- 单件模式(Singleton Pattern)
- Delphi的接口陷阱
- 工作总结
- 常用HTML技术 淘宝店铺装修
- windows下如何使用QT编写dll程序
- Qt4.5与VS2008/VS2005的集成开发环境的安装配置
- 游戏服务器程序的性能思考
- solaris 中的系统log日志原理分析