`
走了弯路的人
  • 浏览: 32734 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论
阅读更多
共享内存可以说是最有用的进程间通信方式,也是最快的IPC(Inter-Process Communication)形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。

采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。

共享内存的使用有如下几个特点:

   1. 可以被多个进程打开访问;
   2. 读写操作的进程在执行读写操作时其他进程不能进行写操作;
   3. 多个进程可以交替对某一共享内存执行写操作;
   4. 一个进程执行了内存的写操作后,不影响其他进程对该内存的访问。同时其他进程对更新后的内存具有可见性。
   5. 在进程执行写操作时如果异常退出,对其他进程写操作禁止应自动解除。
   6. 相对共享文件,数据访问的更方便更效率


另外,共享内存的使用上有如下情况:

独占的写操作,相应有独占的写操作等待队列。独占的写操作本身不会发生数据的一致性问题。
共享的写操作,相应有共享的写操作等待队列。共享的写操作则要注意防止发生数据的一致性问题。
独占的读操作,相应有共享的读操作等待队列;
共享的读操作,相应有共享的读操作等待队列。

共享内存在java中的实现
在jdk1.4中提供的类MappedByteBuffer为我们实现共享内存提供了较好的方法。该缓 冲区实际上是一个磁盘文件的内存映像。二者的变化将保持同步,即内存数据发生变化会立 刻反映到磁盘文件中,这样会有效的保证共享内存的实现。

将共享内存和磁盘文件建立联系的是文件通道类:FileChannel。该类的加入是JDK为了统一对外部设备(文件、网络接口等)的访问方法,并且加强了多线程对同一文件进行存取的安全性。例如读写操作统一成read和write。这里只是用它来建立共享内存用,它建立 了共享内存和磁盘文件之间的一个通道。

打开一个文件建立一个文件通道可以用RandomAccessFile类中的方法getChannel。该方法将直接返回一个文件通道。该文件通道由于对应的文件设为随机存取文件,一方面可以进行读写两种操作,另一方面使用它不会破坏映像文件的内容(如果用FileOutputStream直接打开一个映像文件会将该文件的大小置为0,当然数据会全部丢失)。这里,如果用 FileOutputStream和FileInputStream则不能理想的实现共享内存的要求,因为这两个类同时 实现自由的读写操作要困难得多。

下面的代码实现了如上功能,它的作用类似UNIX系统中的mmap函数。

// 获得一个只读的随机存取文件对象
RandomAccessFile RAFile = new RandomAccessFile(filename,"r");

// 获得相应的文件通道
FileChannel fc = RAFile.getChannel();

// 取得文件的实际大小,以便映像到共享内存
int size = (int)fc.size();

// 获得共享内存缓冲区,该共享内存只读
MappedByteBuffer mapBuf = fc.map(FileChannel.MAP_RO,0,size);

// 获得一个可读写的随机存取文件对象
RAFile = new RandomAccessFile(filename,"rw");

// 获得相应的文件通道
fc = RAFile.getChannel();

// 取得文件的实际大小,以便映像到共享内存
size = (int)fc.size();

// 获得共享内存缓冲区,该共享内存可读写
mapBuf = fc.map(FileChannel.MAP_RW,0,size);

// 获取头部消息:存取权限
mode = mapBuf.getInt();

如果多个应用映像同一文件名的共享内存,则意味着这多个应用共享了同一内存数据。 这些应用对于文件可以具有同等存取权限,一个应用对数据的刷新会更新到多个应用中。

为了防止多个应用同时对共享内存进行写操作,可以在该共享内存的头部信息加入写操 作标志。该共享内存的头部基本信息至少有:
int Length; // 共享内存的长度。
int mode; // 该共享内存目前的存取模式。




共享内存的头部信息是类的私有信息,在多个应用可以对同一共享内存执行写操作时, 开始执行写操作和结束写操作时,需调用如下方法:
public boolean StartWrite()
{
if(mode == 0) { // 标志为0,则表示可写
mode = 1; // 置标志为1,意味着别的应用不可写该共享内存
mapBuf.flip();
mapBuf.putInt(mode); // 写如共享内存的头部信息
return true;
}
else {
return false; // 指明已经有应用在写该共享内存,本应用不可写该共享内存
}
}

public boolean StopWrite()
{
mode = 0; // 释放写权限
mapBuf.flip();
mapBuf.putInt(mode); // 写入共享内存头部信息
return true;
}

这里提供的类文件mmap.java封装了共享内存的基本接口,读者可以用该类扩展成自己 需要的功能全面的类。

如果执行写操作的应用异常中止,那么映像文件的共享内存将不再能执行写操作。为了在应用异常中止后,写操作禁止标志自动消除,必须让运行的应用获知退出的应用。在多线程应用中,可以用同步方法获得这样的效果,但是在多进程中,同步是不起作用的。方法可以采用的多种技巧,这里只是描述一可能的实现:采用文件锁的方式。写共享内存应用在获得对一个共享内存写权限的时候,除了判断头部信息的写权限标志外,还要判断一个临时的锁文件是否可以得到,如果可以得到,则即使头部信息的写权限标志为1(上述),也可以启动写权限,其实这已经表明写权限获得的应用已经异常退出,这段代码如下:
// 打开一个临时的文件,注意同一共享内存,该文件名要相同,可以在共享文件名后加后缀“.lock”。
RandomAccessFile fis = new RandomAccessFile("shm.lock","rw");
// 获得文件通道
FileChannel lockfc = fis.getChannel();
// 获得文件的独占锁,该方法不产生堵塞,立刻返回
FileLock flock = lockfc.tryLock();
// 如果为空,则表明已经有应用占有该锁
if(flock == null) {
...// 不能执行写操作
}
else {
...// 可以执行写操作
}


该锁会在应用异常退出后自动释放,这正是该处所需要的方法。

3 共享内存在java中的应用
共享内存在java应用中,经常有如下两种种应用:

永久对象配置。
在 java服务器应用中,用户可能会在运行过程中配置一些参数,而这些参数需要永久有效,当服务器应用重新启动后,这些配置参数仍然可以对应用起作用。这就可以用到该文中的共享内存。该共享内存中保存了服务器的运行参数和一些对象运行特性。可以在应用启 动时读入以启用以前配置的参数。

查询共享数据。
一个应用是系统的服务进程,其系统的运行状态记录在共享内存中,其中运行状态可能是不断变化的。为了随时了解系统的运行状态,启动另一个应用,该应用查询该共享内存,汇报系统的运行状态。

可见,共享内存在java应用中还是很有用的,只要组织好共享内存的数据结构,共享内存就可以在应用开发中发挥很不错的作用。

分享到:
评论
1 楼 zeng1990 2012-01-03  
请问如何用java的nio的通道实现发送和接收大于缓冲区的数据,并组装回原来的数据。试了很久,都没成功,百度上面也没有相关的文章。求赐教。

相关推荐

    Java共享内存并行编程

    ### Java共享内存并行编程 #### 1. 引言 随着计算机技术的发展,特别是多核处理器的普及,高效利用多核架构成为提高程序性能的关键因素之一。Java作为一种跨平台的语言,不仅在Web开发、企业级应用等领域有着广泛...

    IPC.rar_IPC_java i_java ipc_java共享内存_共享内存

    标题“IPC.rar_IPC_java i_java ipc_java共享内存_共享内存”以及描述“IPC共享内存,文件映射编程,实现原理详解”都指向了一个核心主题:Java中的进程间通信(IPC)以及如何利用共享内存进行数据交换。在这个话题中...

    commons-mmf.rar_java nio_java共享内存_共享内存

    在Java中,可以通过`java.nio.MappedByteBuffer`类来实现共享内存功能,这被称为内存映射文件(Memory-Mapped File,MMF)。 `MappedByteBuffer`是NIO中的一种特殊缓冲区,它将文件的一部分映射到内存中,使得文件...

    使用C#实现共享内存

    VS2005 C# 共享内存 源代码

    java进程间通讯机制代码----RMI、共享内存、Socket、管道

    java进程间通讯机制代码----RMI、共享内存、Socket、管道,等方式,每种方法我都讲了原理和例子程序,很有参考意义。在网上很难找到的。

    Android调用C++实现共享内存

    在Java层,使用`ParcelFileDescriptor`可以创建一个指向共享内存的文件描述符,然后通过Binder传递。在C++层,`Parcel`对象提供了`readFileDescriptor()`和`writeFileDescriptor()`方法来处理文件描述符。 4. **...

    共享内存实现代码shmem

    首先,我们要知道在Unix-like系统(如Linux)中,共享内存主要通过`sys/shm.h`头文件中的函数来操作,比如`shmget`用于创建共享内存,`shmat`用于将共享内存附加到进程地址空间,`shmdt`用于解除共享内存的附加,...

    共享内存示范代码

    共享内存是一种在多进程或线程之间实现高效通信的技术,它允许不同的进程访问同一块物理内存,从而直接交换数据。这个"共享内存示范代码"压缩包包含了一系列与创建和使用共享内存相关的C++源文件,如TestSMDlg.cpp、...

    java实现内存动态分配

    堆内存是Java中的全局共享区域,用于存储所有的对象实例和数组。当通过`new`关键字创建一个新的对象时,其实际的数据结构和属性值都在堆中分配。由于堆内存是所有线程共享的,因此对象实例的创建和访问需要考虑线程...

    Java 内存模型

    总之,Java内存模型是Java编程中的一个基础性话题,它定义了Java程序在多线程环境下关于数据共享、线程通信和同步的规则和约束。深入掌握Java内存模型对于编写高效且正确的Java多线程程序有着不可忽视的作用。程序员...

    Java虚拟机内存管理总结

    Java虚拟机内存管理总结 Java虚拟机(JVM)中的内存管理是指Java语言中对象的分配和释放问题。Java中的内存管理可以分为两部分:对象的分配和释放。 对象的分配是由程序完成的,程序员需要通过关键字new为每个对象...

    java中内存分配

    "java中内存分配" Java 中的内存分配是 Java 程序员必须掌握的重要知识。JAVA 中内存分配的问题是指 Java 程序在运行时如何在内存中存储数据的过程。Java 程序运行时有 6 个地方可以存储数据,它们分别是寄存器、栈...

    Java的内存管理机制分析

    - 堆内存是所有线程共享的,由Java虚拟机自动管理。 - 堆内存的大小可以通过JVM参数来设置,如`-Xms`和`-Xmx`来指定初始大小和最大限制。 3. **数据段(Data Segment)**: - 包括静态域和常量池两部分。 - **...

    深入理解Java内存模型 pdf 超清版

    Java内存模型,简称JMM(Java Memory Model),是Java编程语言规范的一部分,它定义了程序中各个线程如何访问和修改共享变量,以及如何确保数据的一致性。深入理解Java内存模型对于编写高效的并发程序至关重要。本文...

    深入理解Java内存模型

    Java采用的是共享内存模型,线程间通过共享变量来隐式通信。 Java内存模型定义了线程和主内存之间的抽象关系,即所有共享变量存储在主内存中,每个线程都有自己的本地内存,用于存储共享变量的副本。本地内存并不是...

    基于共享内存的hashmap

    标题中的“基于共享内存的HashMap”指的是在多进程或多线程环境中,使用共享内存作为存储机制的哈希映射数据结构。哈希映射(HashMap)是一种常用的数据结构,它通过键值对(key-value pairs)的方式快速存取数据,...

    深入理解Java 虚拟机内存模型.rar

    Java虚拟机(JVM)内存模型是Java编程语言的核心组成部分,它定义了程序运行时的数据区域和内存管理方式。深入理解这一模型对于优化Java应用程序性能、避免内存泄漏以及理解线程安全至关重要。以下是对Java虚拟机...

    Java内存机制学习和使用

    **操作系统和虚拟内存**:现代操作系统通过虚拟内存技术实现了多个进程间的内存共享,每个进程拥有自己独立的虚拟地址空间。操作系统会根据需要在物理内存与交换空间之间动态迁移数据,以优化物理内存的使用效率。 ...

    Java堆栈内存分析笔记

    堆内存是全局的,所有线程共享,它的大小在JVM启动时可以指定。栈内存则是每个线程独享的,其大小由JVM决定,通常较小但处理速度较快。 **堆内存分析** 1. **对象分配**:当创建一个对象时,它的实例数据会存储在...

    java内存模型详解

    Java内存模型,简称JMM(Java Memory Model),是Java虚拟机规范中定义的一个抽象概念,它规定了程序中各个线程如何访问共享变量,以及对这些访问进行同步控制的规则。理解Java内存模型对于编写多线程并发程序至关...

Global site tag (gtag.js) - Google Analytics