大部分情况下,我们面对在两个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. 深究WeixinJSBridge未定义之因

    对于一个没有使用微信JS-SDK的网站来说,我们竟然收到了WeixinJSBridge is not defined 的报错: 去网上一搜,发现很多开发者都遇到类似的问题: 我的微信项目,没有用到微信 ...

  2. Spring Data JPA 简单查询--接口方法

    一.接口方法整理速查 下表针对于简单查询,即JpaRepository接口(继承了CrudRepository接口.PagingAndSortingRepository接口)中的可访问方法进行整理.( ...

  3. Java学习笔记 11/15:一个简单的JAVA例子

    首先来看一个简单的 Java 程序. 来看下面这个程序,试试看是否看得出它是在做哪些事情! 范例:TestJava.java   // TestJava.java,java 的简单范例  public ...

  4. DBMS

    数据库中的概念 Catalog(分类) Table(表) Column(列)或者Field(字段) Primary(主键):唯一标识数据行的一列 业务主键:有业务意义的字段做主键 逻辑主键:使用没有任 ...

  5. Maven——快速入门手册(学习记录)

    前言: 前段时间进行了一点maven的入门学习,在这里做个记录,希望能帮到一些正在学习的朋友们.maven版本为3.3.9.希望大家觉得好的点个赞,觉得不好的多提提意见和建议做个交流.这里也贴出我学习 ...

  6. SQL动态语句 拼接SQL 并输入输出值

    --动态语句语法 /****************************************************************************************** ...

  7. C++ Primer 5 CH5 语句

    5.1 简单语句 空语句: ; 5.2 语句作用域 5.3 条件语句 switch 语句:表达式与某个 case 匹配成功,执行 case 之后的语句直到 break 或者 switch 结尾,cas ...

  8. PHPCMS二次开发——对栏目可用 limit 限定获取

    为了实现类似用limit调用栏目,故自定义了mylimit(这里不能用limit,因为系统在解析的时候会覆盖,所以自定义的limit就起不到作用) 参数,例如: {pc:content  action ...

  9. 新人报道~cnblogs

    我的名字:杨先生 我的英文名:Allen 和你们一样,是一名程序猿,专业技能  C#.前端小块.

  10. 微服务架构的简单实现-Stardust

    微服务架构,一个当下比较火的概念了.以前也只是了解过这方面的概念,没有尝试过.想找找.NET生态下面是否有现成的实现,可是没找到,就花了大半个月的闲暇时间,遵循着易用和简单,实现了一个微服务框架,我叫 ...