大部分情况下,我们面对在两个java进程只见传递数据的问题时,第一个想到的就是开server,然后通过socket收发消息。这方面有大量的框架可用,就不细说了。
但如果两个进程是在一台机器上,那么还可以使用另一种方式来传递数据,那就是使用RandomAccessFile的文件映射模式。
RandomAccessFile的map方法把文件映射到内存中进行快速读写。因此可以通过把消息包写入到文件中,然后另一个进程读取出来的方式来完成数据传递。
在这个过程中,重点是要考虑什么时候写入完成,只有写入完成后,读取进程才可以去读数据,否则就是错误的数据。具体方案如下:
保留文件的首个byte作为标志位,1表示A进程写入完毕,0表示B进程读取完毕。
步骤1:A进程开始写入时,先跳过首字节,然后将数据长度,数据内容写入到文件。写入完毕后,将文件的首字节置为1
步骤2:B进程定时刷新文件到内存中,读取首字节,如果是0则跳出,等待下次刷新。如果是1表示有新数据,则加载。加载完毕后设置首字节为0.表示已经读取完毕。
步骤3:A进程定时刷新文件到内存,读取首字节,如果是0,表示可以写入,继续步骤1的流程。如果是1,则表示数据还没被读取,不可写入。等待下次刷新。
经过以上3个步骤,完成数据的进程间传递。此模式也可以用于将数据传递到非java进程。
代码如下:

public class TestRandomAccessFile {
private static String FileName="aa.a";
private static volatile Linux1 lx1;
private static volatile Linux2 lx2;
private static long from; private static void close(Closeable c){
try{
c.close();
}catch(IOException ie){
ie.printStackTrace();
}
} public static class Linux1{
MappedByteBuffer buf;
RandomAccessFile raf; public Linux1(){
try{
raf = new RandomAccessFile(FileName, "rw");
buf = raf.getChannel().map(MapMode.READ_WRITE, 0, 1024*1024);
}catch(IOException ie){
ie.printStackTrace();
}
new Thread(()->{
try{
while(true){
readAndWrite();
}
}catch(IOException e){
e.printStackTrace();
}
}).start(); } private void readAndWrite() throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String s = reader.readLine();
if(s != null){
if("exit".equalsIgnoreCase(s)){
exitAll();
}else{
write(s);
}
}
} private void write(String s){
if(s.length() == 0)return;
buf.load();
buf.position(0);
byte mark = buf.get();
while(mark != 0){
buf.load();
mark = buf.get();
}
if(s != null && s.length() > 0){
buf.putShort((short)s.length());
for (int i = 0; i< s.length(); i++){
buf.putChar(s.charAt(i));
}
buf.position(0);
buf.put((byte)1); //加可读标记
buf.force();
from = System.nanoTime();
}
} public void exit(){
close(raf);
}
} public static class Linux2{
MappedByteBuffer buf;
RandomAccessFile raf;
public Linux2(){
try{
raf = new RandomAccessFile(FileName, "rw");
buf = raf.getChannel().map(MapMode.READ_WRITE, 0, 1024*1024);
}catch(IOException e){
e.printStackTrace();
} new Thread(()->{
while(true){
checkAndRead();
if(from > 0){
long t = (System.nanoTime()-from);
System.out.println("time=" + t);
from = -1;
}
try{
TimeUnit.NANOSECONDS.sleep(1);
}catch(Exception e){
e.printStackTrace();
}
}
}).start();
} private void checkAndRead(){
buf.load();
if(buf.remaining() == 0)return;
buf.position(0);
byte mark = buf.get();
if(mark == 0)return;
int len = buf.getShort();
if(len > 0){
char[] cs = new char[len];
for (int i = 0; i< len; i++){
cs[i] = buf.getChar();
}
// /System.out.println("***** " + new String(cs));
}
buf.position(0);
buf.put((byte)0);
} public void exit(){
close(raf);
}
} public static void exitAll(){
lx1.exit();
lx2.exit();
System.exit(0);
} public static void main(String[] args){
lx1 = new Linux1();
lx2 = new Linux2();
}
}

测试下来,使用netty走socket传数据,时间在0.5-1ms之间。用RandomAccessFile模式传数据,则依赖于轮询快慢。由于java定时器的误差,及时是用Thread.sleep(0,1)的方式,我们也只能做到平均1ms左右的延迟。但如果是不sleep(现实不能如此,会导致单核被完全占用),那么延迟可以在0.001ms。所以如果能找到一种更有效的轮询方法,那么使用RandomAccessFile进行进程间数据传输的效率会更高,如果不能,那还不如就Socket模式吧,更通用。

使用RandomAccessFile在两个java进程之间传递数据的更多相关文章

  1. 用WM_COPYDATA消息来实现两个进程之间传递数据

    文着重讲述了如果用WM_COPYDATA消息来实现两个进程之间传递数据. 进程之间通讯的几种方法:在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯.常用的方法有   1.使用内存映射 ...

  2. python进程之间修改数据[Manager]与进程池[Pool]

    #前面的队列Queue和管道Pipe都是仅仅能再进程之间传递数据,但是不能修改数据,今天我们学习的东西就可以在进程之间同时修改一份数据 #Mnager就可以实现 import multiprocess ...

  3. 两个java工程之间的相互调用方法

    如果你有两个java项目的话,如何向他们之间进行信息的通信前提:必须知道要通信的java项目(接收请求方)的服务器的IP地址和访问路径.其实两个java项目之间的通信还是使用HTTP的请求.主要有两种 ...

  4. Python 进程之间共享数据

    最近遇到多进程共享数据的问题,到网上查了有几篇博客写的蛮好的,记录下来方便以后查看. 一.Python multiprocessing 跨进程对象共享  在mp库当中,跨进程对象共享有三种方式,第一种 ...

  5. Python 进程之间共享数据(全局变量)

    进程之间共享数据(数值型): import multiprocessing def func(num): num.value=10.78 #子进程改变数值的值,主进程跟着改变 if __name__= ...

  6. Activity之间传递数据的方式及常见问题总结

    Activity之间传递数据一般通过以下几种方式实现: 1. 通过intent传递数据 2. 通过Application 3. 使用单例 4. 静态成员变量.(可以考虑 WeakReferences) ...

  7. Android 笔记-Fragment 与 Activity之间传递数据

    Fragment 与 Activity之间传递数据有两种方法.一种是使用setArgument,一种是使用接口回调.以下先学习第一种方法. (1)使用setArgument方法: 为了便于理解,我在这 ...

  8. Activity之间传递数据或数据包Bundle,传递对象,对象序列化,对象实现Parcelable接口

    package com.gaojinhua.android.activitymsg; import android.content.Intent; import android.os.Bundle; ...

  9. 【Android 复习】 : Activity之间传递数据的几种方式

    在Android开发中,我们通常需要在不同的Activity之间传递数据,下面我们就来总结一下在Activity之间数据传递的几种方式. 1. 使用Intent来传递数据 Intent表示意图,很多时 ...

随机推荐

  1. Eclipse添加tomcat出现 The Apache Tomcat installation at this directory is version 8.5.6. A Tomcat 8.0 installation is expected.

    打开tomcat安装目录:apache-tomcat-8.5.6\lib 找到catalina.jar 用解压缩工具打开 org/apache/catalina/util/ServerInfo.pro ...

  2. HttpServletResponse对象介绍

    一.HttpServletResponse对象介绍

  3. win8和ubuntu双系统

    硬盘安装的话只要分够内存和做好开机启动项就好了,u盘安装要注意分区(挂载)了推荐: http://wenku.baidu.com/view/5052f19b51e79b8968022623.html ...

  4. Spring Data JPA,一种动态条件查询的写法

    我们在使用SpringData JPA框架时,进行条件查询,如果是固定条件的查询,我们可以使用符合框架规则的自定义方法以及@Query注解实现. 如果是查询条件是动态的,框架也提供了查询接口. Jpa ...

  5. C#生成漂亮验证码完整代码类

    using System;using System.Web;using System.Drawing;using System.Security.Cryptography; namespace Dot ...

  6. eclipse扩容

    -vmD:/jdk-6u17-windows-i586/jdk1.6.0_17/bin/javaw.exe-startupplugins/org.eclipse.equinox.launcher_1. ...

  7. SQL Server 备份所有数据库代码

    今天让我备份一下网上所有数据库,猛地一看,几百个呢, 坑爹呢,只好网上找找有没有简便的,没想到还真有 记下来,以后好用,哈哈... use master declare @DbName varchar ...

  8. [SinGuLaRiTy] 字节大小

    [SinGuLaRiTy-1006] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 16位编译器 char 1个字节 char*(即指针变量 ...

  9. 搞定:Enter passphrase for key提示

    使用ssh-genkey生成公用key,但是自己使用时会多次提示,Enter passphrase for key,这儿给出如何解决. 在${HOME}/.bashrc中增加如下代码: alias a ...

  10. 常见的Java面试题整理

    面试是我们每个人都要经历的事情,大部分人且不止一次,这里给大家总结常见的面试题,让大家在找工作时候能够事半功倍. 1 Switch能否用string做参数? a.在 Java 7 之前, switch ...