java实现共享内存操作

 

    对UNIX系统来说,共享内存分为一般共享内存和映像文件共享内存两种,对windows实际上只有映像文件共享内存一种。所以java应用中也是只能创建映像文件共享内存。使用共享内存,有如下几个特点:

1、可以被多个进程打开访问。

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

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

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

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

 

一般我们操作共享内存有以下几种情况,主要关注1,2:

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

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

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

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

 

在jdk1.4中提供的类MappedByteBuffer为我们提供了实现共享内存的方法,该缓冲区实际上是一个磁盘文件的内存映像。二者的变化保持同步,即内存数据发生变化会立刻反应到磁盘文件中,这样会有效的保证共享内存的实现。废话不多说,直接看代码:

package com.hx.sharemem;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.Properties;

import com.hx.util.FileUtil;


/**
 * 共享内存操作类
 * @author hx
 *
 */
public class ShareMemory {

	int flen = 41779264;					//开辟共享内存大小
	int fsize = 0;							//文件的实际大小
	String shareFileName;					//共享内存文件名
	String sharePath;						//共享内存路径
	MappedByteBuffer mapBuf = null;			//定义共享内存缓冲区
	FileChannel fc = null;					//定义相应的文件通道
	FileLock fl = null;						//定义文件区域锁定的标记。		
	Properties p = null;
	RandomAccessFile RAFile = null;			//定义一个随机存取文件对象

	/**
	 * 
	 * @param sp	共享内存文件路径
	 * @param sf	共享内存文件名
	 */
	public ShareMemory(String sp, String sf) {
		if (sp.length() != 0) {
			FileUtil.CreateDir(sp);
			this.sharePath = sp + File.separator;
		} else {
			this.sharePath = sp;
		}
		this.shareFileName = sf;

		try {
			// 获得一个只读的随机存取文件对象   "rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。  
			RAFile = new RandomAccessFile(this.sharePath + this.shareFileName + ".sm", "rw");
			//获取相应的文件通道
			fc = RAFile.getChannel();
			//获取实际文件的大小
			fsize = (int) fc.size();
			if (fsize < flen) {
				byte bb[] = new byte[flen - fsize];
				//创建字节缓冲区
				ByteBuffer bf = ByteBuffer.wrap(bb);
				bf.clear();
				//设置此通道的文件位置。 
				fc.position(fsize);
				//将字节序列从给定的缓冲区写入此通道。
				fc.write(bf);
				fc.force(false);

				fsize = flen;
			}
			//将此通道的文件区域直接映射到内存中。
			mapBuf = fc.map(FileChannel.MapMode.READ_WRITE, 0, fsize);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * @param ps		锁定区域开始的位置;必须为非负数
	 * @param len		锁定区域的大小;必须为非负数
	 * @param buff		写入的数据
	 * @return
	 */
	public synchronized int write(int ps, int len, byte[] buff) {
		if (ps >= fsize || ps + len >= fsize) {
			return 0;
		}
		//定义文件区域锁定的标记。
		FileLock fl = null;
		try {
			//获取此通道的文件给定区域上的锁定。 
			fl = fc.lock(ps, len, false);
			if (fl != null) {

				mapBuf.position(ps);
				ByteBuffer bf1 = ByteBuffer.wrap(buff);
				mapBuf.put(bf1);
				//释放此锁定。
				fl.release();

				return len;
			}
		} catch (Exception e) {
			if (fl != null) {
				try {
					fl.release();
				} catch (IOException e1) {
					System.out.println(e1.toString());
				}
			}
			return 0;
		}

		return 0;
	}
	
	/**
	 * 
	 * @param ps		锁定区域开始的位置;必须为非负数
	 * @param len		锁定区域的大小;必须为非负数
	 * @param buff		要取的数据
	 * @return
	 */
	public synchronized int read(int ps, int len, byte[] buff) {
		if (ps >= fsize) {
			return 0;
		}
		//定义文件区域锁定的标记。
		FileLock fl = null;
		try {
			fl = fc.lock(ps, len, false);
			if (fl != null) {
				//System.out.println( "ps="+ps );
				mapBuf.position(ps);
				if (mapBuf.remaining() < len) {
					len = mapBuf.remaining();
				}

				if (len > 0) {
					mapBuf.get(buff, 0, len);
				}

				fl.release();

				return len;
			}
		} catch (Exception e) {
			if (fl != null) {
				try {
					fl.release();
				} catch (IOException e1) {
					System.out.println(e1.toString());
				}
			}
			return 0;
		}

		return 0;
	}
	
	/**
	 * 完成,关闭相关操作
	 */
	protected void finalize() throws Throwable {
		if (fc != null) {
			try {
				fc.close();
			} catch (IOException e) {
				System.out.println(e.toString());
			}
			fc = null;
		}

		if (RAFile != null) {
			try {
				RAFile.close();
			} catch (IOException e) {
				System.out.println(e.toString());
			}
			RAFile = null;
		}
		mapBuf = null;
	}
	
	/**
	 * 关闭共享内存操作
	 */
	public synchronized void closeSMFile() {
		if (fc != null) {
			try {
				fc.close();
			} catch (IOException e) {
				System.out.println(e.toString());
			}
			fc = null;
		}

		if (RAFile != null) {
			try {
				RAFile.close();
			} catch (IOException e) {
				System.out.println(e.toString());
			}
			RAFile = null;
		}
		mapBuf = null;
	}
	
	/**
	 *  检查退出
	 * @return	true-成功,false-失败
	 */
	public synchronized boolean checkToExit() {
		byte bb[] = new byte[1];

		if (read(1, 1, bb) > 0) {
			if (bb[0] == 1) {
				return true;

			}
		}

		return false;
	}

	/**
	 * 复位退出
	 */
	public synchronized void resetExit() {
		byte bb[] = new byte[1];

		bb[0] = 0;
		write(1, 1, bb);

	}

	/**
	 * 退出
	 */
	public synchronized void toExit() {
		byte bb[] = new byte[1];

		bb[0] = 1;
		write(1, 1, bb);

	}
	
	public static void main(String arsg[]) throws Exception{
		ShareMemory sm = new ShareMemory("E://demo","test");
		String str = "中文测试";
		sm.write(40, 20, str.getBytes("UTF-8"));
		byte[] b = new byte[20];
		sm.read(40, 20, b);
		System.out.println(new String(b,"UTF-8"));
	}
}

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值