转自: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, 01024);
 
        //清除文件内容
        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, 01024);
        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 进程间通信的更多相关文章

  1. java nio系列文章

    java nio系列教程 基于NIO的Client/Server程序实践 (推荐) java nio与并发编程相关电子书籍   (访问密码 48dd) 理解NIO nio学习记录 图解ByteBuff ...

  2. JAVA NIO之文件通道

    1.简介 通道是 Java NIO 的核心内容之一,在使用上,通道需和缓存类(ByteBuffer)配合完成读写等操作.与传统的流式 IO 中数据单向流动不同,通道中的数据可以双向流动.通道既可以读, ...

  3. 源码分析netty服务器创建过程vs java nio服务器创建

    1.Java NIO服务端创建 首先,我们通过一个时序图来看下如何创建一个NIO服务端并启动监听,接收多个客户端的连接,进行消息的异步读写. 示例代码(参考文献[2]): import java.io ...

  4. 支撑Java NIO 与 NodeJS的底层技术

    支撑Java NIO 与 NodeJS的底层技术 众所周知在近几个版本的Java中增加了一些对Java NIO.NIO2的支持,与此同时NodeJS技术栈中最为人称道的优势之一就是其高性能IO,那么我 ...

  5. JAVA NIO学习笔记1 - 架构简介

    最近项目中遇到不少NIO相关知识,之前对这块接触得较少,算是我的一个盲区,打算花点时间学习,简单做一点个人学习总结. 简介 NIO(New IO)是JDK1.4以后推出的全新IO API,相比传统IO ...

  6. Java NIO概述

    Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然 Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Se ...

  7. JAVA NIO Socket通道

      DatagramChannel和SocketChannel都实现定义读写功能,ServerSocketChannel不实现,只负责监听传入的连接,并建立新的SocketChannel,本身不传输数 ...

  8. JAVA NIO FileChannel 内存映射文件

      文件通道总是阻塞式的. 文件通道不能创建,只能通过(RandomAccessFile.FileInputStream.FileOutputStream)getChannel()获得,具有与File ...

  9. Java NIO (转)

    Java NIO提供了与标准IO不同的IO工作方式: Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(B ...

随机推荐

  1. Linux命令行获取本机外网IP地址

    问题: 服务器地址为net映射地址,本机ifconfig无法直接获取映射的公网地址. 方法: [root@TiaoBan- nidongde]# curl http://ifconfig.me 50. ...

  2. 数字签名、数字证书的原理以及证书的获得java版

    数字签名原理简介(附数字证书) 首先要了解什么叫对称加密和非对称加密,消息摘要这些知识. 1. 非对称加密 在通信双方,如果使用非对称加密,一般遵从这样的原则:公钥加密,私钥解密.同时,一般一个密钥加 ...

  3. 微擎开启redis memcache文档2

    微擎开启redis memcache 2018年01月20日 14:39:54 luogan129 阅读数:2161更多 个人分类: 微信开发   版权声明:本文为博主原创文章,未经博主允许不得转载. ...

  4. delphi 窗体自适应屏幕分辨率

    delphi 窗体自适应屏幕分辨率 这是个困惑我很长时间的问题,到今天终于得到解决了. 话说Delphi有个很强的窗体设计器,这一点让VC粉丝垂涎三尺而不可得.但是,Delphi里设计的窗体并没有自动 ...

  5. WebAPI中发送字节数组

    今天工作中遇到了一个情景: 前端向后台发送一个请求,希望后台返回一组数据,由于后台返回的数据量很大,希望尽可能压缩响应的大小 我的想法:后台将数据(Short的数组)直接转换成Byte[]  然后将b ...

  6. C#项目 学生选课系统 C#窗口 Winform项目 项目源码及使用说明

    这是一个学生选课信息管理系统,使用VS2010+SQL2008编写,VS2017正常使用. 项目源码下载地址 https://gitee.com/whuanle/xkgl 笔者录了两个视频,打开项目源 ...

  7. 为什么要使用Entity Framework

    本文介绍从DDD(Domain-Driven Design[领域驱动设计])的角度来说说为什么要使用Entity Framework(以下都会简称为EF),同时也看出类似Drapper之类的简陋ORM ...

  8. MariaDB 主从同步与热备(14)

    MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可MariaDB的目的是完全兼容MySQL,包括API和命令行,MySQL由于现在闭源了,而能轻松成为MySQ ...

  9. 伪装为 吃鸡账号获取器 的QQ木马分析

    本文作者:i春秋作家坏猫叔叔 0×01 起因随着吃鸡热潮的来临,各种各样的吃鸡辅助和账号交易也在互联网的灰色地带迅速繁殖滋生.其中有真有假,也不乏心怀鬼胎的“放马人”.吃过晚饭后在一个论坛看到了这样一 ...

  10. Android常用布局属性解析 -- Layout_weight

    Layout_weight是Android开发中一个比较常用的布局属性,在面试中也经常被问到.下面通过实例彻底搞懂Layout_weight的用法. 先看下面的布局代码: <?xml versi ...