Java NIO 进程间通信
转自:http://blog.csdn.net/lingzhm/article/details/45026119
传统的进程间通信的方式有大致如下几种:
(1) 管道(PIPE)
(2) 命名管道(FIFO)
(3) 信号量(Semphore)
(4) 消息队列(MessageQueue)
(5) 共享内存(SharedMemory)
(6) Socket
Java如何支持进程间通信。我们把Java进程理解为JVM进程。很明显,传统的这些大部分技术是无法被我们的应用程序利用了(这些进程间通信都是靠系统调用来实现的)。但是Java也有很多方法可以进行进程间通信的。
除了上面提到的Socket之外,当然首选的IPC可以使用Rmi,或者Corba也可以。另外Javanio的MappedByteBuffer也可以通过内存映射文件来实现进程间通信(共享内存)。
Java进程间通信可以采用的办法:
Socket/RMI/WEBService/WebServer, 这些都可以实现直接的数据交换
Database/File, 这些可以实现间接的数据交换
看你的业务是否要求实时, 如果不需要, 用数据库交换比较简单
线程间通信:
可以直接传入共享的变量来实现。
一看到 javaNIO 的内存映射文件(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
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
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
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
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中实现和应用
Java NIO 进程间通信的更多相关文章
- java nio系列文章
java nio系列教程 基于NIO的Client/Server程序实践 (推荐) java nio与并发编程相关电子书籍 (访问密码 48dd) 理解NIO nio学习记录 图解ByteBuff ...
- JAVA NIO之文件通道
1.简介 通道是 Java NIO 的核心内容之一,在使用上,通道需和缓存类(ByteBuffer)配合完成读写等操作.与传统的流式 IO 中数据单向流动不同,通道中的数据可以双向流动.通道既可以读, ...
- 源码分析netty服务器创建过程vs java nio服务器创建
1.Java NIO服务端创建 首先,我们通过一个时序图来看下如何创建一个NIO服务端并启动监听,接收多个客户端的连接,进行消息的异步读写. 示例代码(参考文献[2]): import java.io ...
- 支撑Java NIO 与 NodeJS的底层技术
支撑Java NIO 与 NodeJS的底层技术 众所周知在近几个版本的Java中增加了一些对Java NIO.NIO2的支持,与此同时NodeJS技术栈中最为人称道的优势之一就是其高性能IO,那么我 ...
- JAVA NIO学习笔记1 - 架构简介
最近项目中遇到不少NIO相关知识,之前对这块接触得较少,算是我的一个盲区,打算花点时间学习,简单做一点个人学习总结. 简介 NIO(New IO)是JDK1.4以后推出的全新IO API,相比传统IO ...
- Java NIO概述
Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然 Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Se ...
- JAVA NIO Socket通道
DatagramChannel和SocketChannel都实现定义读写功能,ServerSocketChannel不实现,只负责监听传入的连接,并建立新的SocketChannel,本身不传输数 ...
- JAVA NIO FileChannel 内存映射文件
文件通道总是阻塞式的. 文件通道不能创建,只能通过(RandomAccessFile.FileInputStream.FileOutputStream)getChannel()获得,具有与File ...
- Java NIO (转)
Java NIO提供了与标准IO不同的IO工作方式: Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(B ...
随机推荐
- Vue的配置
一.build:打包的配置文件的文件夹 1.build.js 生产版本的配置文件,一般这个文件我们是不改的 'use strict' //调用检查版本的文件,check-versions的导出直接是 ...
- 冲刺博客NO.3
今天做了什么:参考网上的一些登录界面,发现了Android studio自带loginActivity.做了基础登录界面 不停地上网搜,各种不会. 在短信验证功能上通过在Mob.com的集成文档和官 ...
- Android之TextView灵活使用
Android之TextView灵活使用 在项目中有无遇到过这样一种程况,例如文字"王明今年10岁了", 但是数字10是从网络返回的数据, 而你又想把这个文字写在xml中, 过往我 ...
- hive 实现类似 contain 包含查询
如何用hive sql 实现 contain 查询? 需求:判断某个字符串是否在另一个字符串中? 方法: 可以自定义函数,但是用正则匹配regexp更方便 代码如下: 首先,查看regexp正则函数的 ...
- UITableView横向滚动
UITableView 设置 CGRect tableViewRect = CGRectMake(0.0, 0.0, 50.0, 320.0); self.tableView = [[UITableV ...
- Windows 下环境变量设置(命令行)
0. 背景 查了一下 SETX 命令可以实现,先简单看了下帮助.以后再写一个实例. 1. SETX /? 输出内容: SetX 有三种使用方式: 语法 1: SETX [/S system [/ ...
- EF三种编程方式详细图文教程(C#+EF)之Database First
Entity Framework4.1之前EF支持“Database First”和“Model First”编程方式,从EF4.1开始EF开始支持支持“Code First”编程方式,今天简单看一下 ...
- [UWP开发] 在低版本中使用亚克力刷以及部分高版本控件
写于2018.10.3 仅在我的PC(17763)和WP(Limia 950 XL 15254)上测试过 微软在build 16299中引入了亚克力刷,但是Win10m并没有活那么久,lumia手机在 ...
- Codeforces Round #425 (Div. 2) B. Petya and Exam(字符串模拟 水)
题目链接:http://codeforces.com/contest/832/problem/B B. Petya and Exam time limit per test 2 seconds mem ...
- Shell - 简明Shell入门11 - 调用脚本(CallTheScript)
示例脚本及注释 主脚本: CallTheScript.sh #!/bin/bash . ./11-subscript.sh # 调用其他脚本;注意点号"."和文件路径之间有一空格; ...