Java NIO 进程间通信
来源:互联网 发布:js的display 编辑:程序博客网 时间:2024/05/18 18:42
传统的进程间通信的方式有大致如下几种:
(1) 管道(PIPE)
(2) 命名管道(FIFO)
(3) 信号量(Semphore)
(4) 消息队列(MessageQueue)
(5) 共享内存(SharedMemory)
(6) Socket
Java如何支持进程间通信。我们把Java进程理解为JVM进程。很明显,传统的这些大部分技术是无法被我们的应用程序利用了(这些进程间通信都是靠系统调用来实现的)。但是Java也有很多方法可以进行进程间通信的。
除了上面提到的Socket之外,当然首选的IPC可以使用Rmi,或者Corba也可以。另外Java nio的MappedByteBuffer也可以通过内存映射文件来实现进程间通信(共享内存)。
Java进程间通信可以采用的办法:
Socket/RMI/WEBService/WebServer, 这些都可以实现直接的数据交换
Database/File, 这些可以实现间接的数据交换
看你的业务是否要求实时, 如果不需要, 用数据库交换比较简单
线程间通信:
可以直接传入共享的变量来实现。
一看到 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
package
com.unmi;
import
java.io.RandomAccessFile;
import
java.nio.MappedByteBuffer;
import
java.nio.channels.FileChannel;
import
java.nio.channels.FileChannel.MapMode;
/**
* 往 "共享内存" 写入数据
* @author Unmi
*/
public
class
WriteShareMemory {
/**
* @param args
* @throws Exception
*/
public
static
void
main(String[] args)
throws
Exception {
RandomAccessFile raf =
new
RandomAccessFile(
"c:/swap.mm"
,
"rw"
);
FileChannel fc = raf.getChannel();
MappedByteBuffer mbb = fc.map(MapMode.READ_WRITE,
0
,
1024
);
//清除文件内容
for
(
int
i=
0
;i<
1024
;i++){
mbb.put(i,(
byte
)
0
);
}
//从文件的第二个字节开始,依次写入 A-Z 字母,第一个字节指明了当前操作的位置
for
(
int
i=
65
;i<
91
;i++){
int
index = i-
63
;
int
flag = mbb.get(
0
);
//可读标置第一个字节为 0
if
(flag !=
0
){
//不是可写标示 0,则重复循环,等待
i --;
continue
;
}
mbb.put(
0
,(
byte
)
1
);
//正在写数据,标志第一个字节为 1
mbb.put(
1
,(
byte
)(index));
//写数据的位置
System.out.println(
"程序 WriteShareMemory:"
+System.currentTimeMillis() +
":位置:"
+ index +
" 写入数据:"
+ (
char
)i);
mbb.put(index,(
byte
)i);
//index 位置写入数据
mbb.put(
0
,(
byte
)
2
);
//置可读数据标志第一个字节为 2
Thread.sleep(
513
);
}
}
}
ReadShareMemory.java
package
com.unmi;
import
java.io.RandomAccessFile;
import
java.nio.MappedByteBuffer;
import
java.nio.channels.FileChannel;
import
java.nio.channels.FileChannel.MapMode;
/**
* 从 "共享内存" 读出数据
* @author Unmi
*/
public
class
ReadShareMemory {
/**
* @param args
* @throws Exception
*/
public
static
void
main(String[] args)
throws
Exception {
RandomAccessFile raf =
new
RandomAccessFile(
"c:/swap.mm"
,
"rw"
);
FileChannel fc = raf.getChannel();
MappedByteBuffer mbb = fc.map(MapMode.READ_WRITE,
0
,
1024
);
int
lastIndex =
0
;
for
(
int
i=
1
;i<
27
;i++){
int
flag = mbb.get(
0
);
//取读写数据的标志
int
index = mbb.get(
1
);
//读取数据的位置,2 为可读
if
(flag !=
2
|| index == lastIndex){
//假如不可读,或未写入新数据时重复循环
i--;
continue
;
}
lastIndex = index;
System.out.println(
"程序 ReadShareMemory:"
+ System.currentTimeMillis() +
":位置:"
+ index +
" 读出数据:"
+ (
char
)mbb.get(index));
mbb.put(
0
,(
byte
)
0
);
//置第一个字节为可读标志为 0
if
(index ==
27
){
//读完数据后退出
break
;
}
}
}
}
在 Eclipse 中运行 WriteShareMemory,然后到命令行下运行 ReadShareMemory,你将会看到 WriteShareMemory 写一个字符,ReadShareMemory 读一个。
代码中使用了读写标志位,和写入的索引位置,所以在 WriteShareMemory 写入一个字符后,只有等待 ReadShareMemory 读出刚写入的字符后才会写入第二个字符。实际应用中可以加入更好的通知方式,如文件锁等。
你也可以查看执行时 c:\swap.mm 文件的内容来验证这一过程,因为 MappedByteBuffer 在运行时是一种 DirectByteBuffer,所以它能与文件即时的同步内容,无须通过 FileChannel 来 write(buffer) 往文件中手工写入数据,或 read(buffer) 手工读数据到内存中。
参考:1. 共享内存在Java中实现和应用
本文链接 http://unmi.cc/java-nio-memory-mapping-communicate/, 来自 隔叶黄莺 Unmi Blog
[版权声明] 本文采用署名-非商业性使用-相同方式共享 2.5 通用 (CC BY-NC-SA 2.5) 进行许可。
- Java NIO 进程间通信
- Java NIO 内存映射文件实现进程间通信
- java nio 使用内存映射文件实现进程间通信
- Java NIO 内存映射文件实现进程间通信
- Java NIO 应用 -- 使用内存映射文件实现进程间通信
- java进程间通信
- java进程间通信:
- java进程间通信
- Java进程间通信
- Java NIO通信
- Java Nio通信
- Java NIO Socket通信
- Java NIO Socket通信
- Java NIO Socket通信
- java NIO Socket通信
- Java NIO Socket通信
- java nio学习之 socket+nio 通信
- 【转】Java进程间通信
- java实现二叉树的多种遍历
- java术语(PO/POJO/VO/BO/DAO/DTO)
- 80后的北漂IT人:你的未来在哪?该做好打算了!
- Android使用wifi Ap核心类
- 获取手机中内外存储卡
- Java NIO 进程间通信
- Makefile编译取消回显
- iOS block的用法
- 2、广域网基础知识……
- Xms Xmx PermSize MaxPermSize 区别
- GDB详解
- SqlBulkCopy使用Demo
- C程序编译过程浅析
- Linked List Cycle