Java 共享内存

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

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

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

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

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

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

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

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

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

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

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

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

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;




/**
 * 共享内存操作类
 * @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) {
            File folder = new File(sp);
            if(!folder.exists()){
                folder.mkdirs();
            }
        }

        this.sharePath = sp + File.separator;
        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;
    }

    /**
     * 关闭共享内存操作
     */
    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 = "中文测试";
        byte[] bytes = str.getBytes("UTF-8");
        int byteLength = bytes.length;
        System.out.println(byteLength);
        sm.write(40, byteLength, bytes);
        byte[] b = new byte[byteLength];
        sm.read(40, byteLength, b);
        System.out.println(new String(b,"UTF-8"));
    }
}

猜你喜欢

转载自blog.csdn.net/haoranhaoshi/article/details/91460898
今日推荐