文档章节

共享内存在Java中的实现和应用

涩女郎
 涩女郎
发布于 2015/04/23 10:59
字数 2543
阅读 540
收藏 1
点赞 0
评论 0

共享内存对应应用开发的意义

对熟知UNIX系统应用开发的程序员来说,IPC(InterProcess Communication)机制是 非常熟悉的,IPC基本包括共享内存、信号灯操作、消息队列、信号处理等部分,是开发应 用中非常重要的必不可少的工具。其中共享内存IPC机制的关键,对于数据共享、系统快 速查询、动态配置、减少资源耗费等均有独到的优点。

对应UNIX系统来说,共享内存分为一般共享内存和映像文件共享内存两种,而对应 Windows,实际上只有映像文件共享内存一种。所以java应用中也是只能创建映像文件共享 内存。

在java语言中,基本上没有提及共享内存这个概念,但是,在某一些应用中,共享内 存确实非常有用,例如采用java语言的分布式应用系统中,存在着大量的分布式共享对象, 很多时候需要查询这些对象的状态,以查看系统是否运行正常或者了解这些对象的目前的一 些统计数据和状态。如果采用网络通信的方式,显然会增加应用的额外负担,也增加了一些 不必要的应用编程。而如果采用共享内存的方式,则可以直接通过共享内存查看对象的状态 数据和统计数据,从而减少了一些不必要的麻烦。

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

  1. 可以被多个进程打开访问;

  2. 读写操作的进程在执行读写操作时其他进程不能进行写操作;

  3. 多个进程可以交替对某一共享内存执行写操作;

  4. 一个进程执行了内存的写操作后,不影响其他进程对该内存的访问。同时其他进程对更新后的内存具有可见性。

  5. 在进程执行写操作时如果异常退出,对其他进程写操作禁止应自动解除。

  6. 相对共享文件,数据访问的方便性和效率有

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

  1. 独占的写操作,相应有独占的写操作等待队列。独占的写操作本身不会发生数据的一致性问题。

  2. 共享的写操作,相应有共享的写操作等待队列。共享的写操作则要注意防止发生数据的一致性问题。

  3. 独占的读操作,相应有共享的读操作等待队列;

  4. 共享的读操作,相应有共享的读操作等待队列。

一般情况下,我们只是关心第一二种情况。

共享内存在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 {
...// 可以执行写操作
}

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

共享内存在java中的应用

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

  1. 永久对象配置。

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

  2. 查询共享数据。

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

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


© 著作权归作者所有

共有 人打赏支持
涩女郎
粉丝 35
博文 104
码字总数 160210
作品 0
浦东
高级程序员
JVM内存结构 VS Java内存模型 VS Java对象模型

Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模型和...

Java架构
07/11
0
0
Java高级-解析Java中的多线程机制

一、进程与应用程序的区别 进程(Process)是最初定义在Unix等多用户、多任务操作系统环境下用于表示应用程序在内存环境中基本执行单元的概念。以Unix操作系统为例,进程是Unix操作系统环境中...

陶邦仁
2012/11/11
0
0
Java虚拟机(JVM)(自动内存管理机制)

简介 Java虚拟机(JVM)是Java应用的运行环境,从一般意义上来讲,JVM是通过规范来定义的一个虚拟的计算机,被设计用来解释执行从Java源码编译而来的字节码。 体系结构 JVM主要有子系统和内存...

亚特兰缇斯
2015/03/05
0
0
Terrocotta - 基于JVM的Java应用集群解决方案

越来越多的企业关键应用都必须采用集群技术,实现负载均衡(Load Balancing)、容错(Fault Tolerance)和灾难恢复(Failover)。以达到系统可用性(High Availability)和可伸缩性(Scalabi...

阿秀a
2010/10/17
0
0
ThreadLocal实现线程范围的共享变量

hreadLocal的作用和目的:用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一个线程中运行时要共享一份数据,而在另一个线程中则共享另一份数据,线程的数据是独享的。 Thread...

凯文加内特
2014/03/22
0
0
加强Docker容器与Java 10集成

很多运行在Java虚拟机(JVM)中的应用,包括数据服务如Apache Spark和Kafka以及传统企业应用,都运行在容器中。最近,运行在容器里的JVM出现了由于内存和CPU资源限制和使用率导致性能损失问题...

java高级架构牛人
06/04
0
0
Java堆和栈的区别和介绍以及JVM的堆和栈

Java堆和栈的区别和介绍以及JVM的堆和栈 一、Java的堆内存和栈内存 Java把内存划分成两种:一种是堆内存,一种是栈内存。 堆:主要用于存储实例化的对象,数组。由JVM动态分配内存空间。一个...

代金券优惠
05/24
0
0
集群中几种Session同步方案比较

在集群中session安全和同步是个最大的问题,下面是收集到的几种session同步的方案,希望能通过分析其各自的优劣找出其适应的场景。 1. 客户端cookie加密 简单,高效。比较好的方法是自己采用...

哎哎哎哎啊
2013/05/30
0
0
Java堆和栈的区别,JVM的堆和栈的介绍

一、Java的堆内存和栈内存 Java把内存划分成两种:一种是堆内存,一种是栈内存。 堆:主要用于存储实例化的对象,数组。由JVM动态分配内存空间。一个JVM只有一个堆内存,线程是可以共享数据的...

光明辉煌
05/21
0
0
实际项目中是选用Map还是选用Redis作为缓存?为什么?

参考网页 https://segmentfault.com/q/1010000009106416 实际项目中是选用Map还是选用Redis作为缓存?为什么? 具体选择Map还是Redis作为缓存,要看具体的需求,具体的应用场景 本地缓存和分...

karma123
06/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

前端基础

1. get请求传参长度的误区 误区:我们经常说get请求参数的大小存在限制,而post请求的参数大小是无限制的。 实际上HTTP 协议从未规定 GET/POST 的请求长度限制是多少。对get请求参数的限制是...

wenxingjun
今天
0
0
Android 复制和粘贴功能

做了一回搬运工,原文地址:https://blog.csdn.net/kennethyo/article/details/76602765 Android 复制和粘贴功能,需要调用系统服务ClipboardManager来实现。 ClipboardManager mClipboardM...

她叫我小渝
今天
0
0
拦截SQLSERVER的SSL加密通道替换传输过程中的用户名密码实现运维审计(一)

工作准备 •一台SQLSERVER 2005/SQLSERVER 2008服务 •SQLSERVER jdbc驱动程序 •Java开发环境eclipse + jdk1.8 •java反编译工具JD-Core 反编译JDBC分析SQLSERVER客户端与服务器通信原理 SQ...

紅顏為君笑
今天
6
0
jQuery零基础入门——(六)修改DOM结构

《jQuery零基础入门》系列博文是在廖雪峰老师的博文基础上,可能补充了个人的理解和日常遇到的点,用我的理解表述出来,主干出处来自廖雪峰老师的技术分享。 在《零基础入门JavaScript》的时...

JandenMa
今天
0
0
linux mint 1.9 qq 安装

转: https://www.jianshu.com/p/cdc3d03c144d 1. 下载 qq 轻聊版,可在百度搜索后下载 QQ7.9Light.exe 2. 去wine的官网(https://wiki.winehq.org/Ubuntu) 安装 wine . 提醒网页可以切换成中...

Canaan_
今天
0
0
PHP后台运行命令并管理运行程序

php后台运行命令并管理后台运行程序 class ProcessModel{ private $pid; private $command; private $resultToFile = ''; public function __construct($cl=false){......

colin_86
今天
1
0
数据结构与算法4

在此程序中,HighArray类中的find()方法用数据项的值作为参数传递,它的返回值决定是否找到此数据项。 insert()方法向数组下一个空位置放置一个新的数据项。一个名为nElems的字段跟踪记录着...

沉迷于编程的小菜菜
今天
1
1
fiddler安装和基本使用以及代理设置

项目需求 由于开发过程中客户端和服务器数据交互非常频繁,有时候服务端需要知道客户端调用接口传了哪些参数过来,这个时候就需要一个工具可以监听这些接口请求参数,已经接口的响应的数据,这种...

银装素裹
今天
0
0
Python分析《我不是药神》豆瓣评论

读取 Mongo 中的短评数据,进行中文分词 对分词结果取 Top50 生成词云 生成词云效果 看来网上关于 我不是药神 vs 达拉斯 的争论很热啊。关于词频统计就这些,代码中也会完成一些其它的分析任...

猫咪编程
今天
0
0
虚拟机怎么安装vmware tools

https://blog.csdn.net/tjcwt2011/article/details/72638977

AndyZhouX
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部