实际上,Util.newMappedByteBuffer() 方法通过反射机制获取 DirectByteBuffer 的构造器,然后创建一个 DirectByteBuffer 的实例,对应的是一个单独用于内存映射的构造方法:
- protected DirectByteBuffer(int cap, long addr, FileDescriptor fd, Runnable unmapper) {
- super(-1, 0, cap, cap, fd);
- address = addr;
- cleaner = Cleaner.create(this, unmapper);
- att = null;
- }
我们需要关注的是,DirectByteBuffer 在 MappedByteBuffer 的基础上提供了内存映像文件的随机读取 get() 和写入 write() 的操作 。
内存映像文件的随机读操作:
- public byte get() {
- return ((unsafe.getByte(ix(nextGetIndex()))));
- }
- public byte get(int i) {
- return ((unsafe.getByte(ix(checkIndex(i)))));
- }
- public ByteBuffer put(byte x) {
- unsafe.putByte(ix(nextPutIndex()), ((x)));
- return this;
- }
- public ByteBuffer put(int i, byte x) {
- unsafe.putByte(ix(checkIndex(i)), ((x)));
- return this;
- }
- private long ix(int i) {
- return address + ((long)i << 0);
- }
FileChannel 是一个用于文件读写、映射和操作的通道,同时它在并发环境下是线程安全的 。
基于 FileInputStream、FileOutputStream 或者 RandomaccessFile 的 getChannel() 方法可以创建并打开一个文件通道 。
FileChannel 定义了 transferFrom() 和 transferTo() 两个抽象方法,它通过在通道和通道之间建立连接实现数据传输的 。
transferTo():通过 FileChannel 把文件里面的源数据写入一个 WritableByteChannel 的目的通道 。
- public abstract long transferTo(long position, long count, WritableByteChannel target)
- throws IOException;
- public abstract long transferFrom(ReadableByteChannel src, long position, long count)
- throws IOException;
- private static final String CONTENT = "Zero copy implemented by FileChannel";
- private static final String SOURCE_FILE = "/source.txt";
- private static final String TARGET_FILE = "/target.txt";
- private static final String CHARSET = "UTF-8";
- @Before
- public void setup() {
- Path source = Paths.get(getClassPath(SOURCE_FILE));
- byte[] bytes = CONTENT.getBytes(Charset.forName(CHARSET));
- try (FileChannel fromChannel = FileChannel.open(source, StandardOpenOption.READ,
- StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
- fromChannel.write(ByteBuffer.wrap(bytes));
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
其中,FileChannel、SocketChannel 和 DatagramChannel 等通道实现了 WritableByteChannel 和 ReadableByteChannel 接口,都是同时支持读写的双向通道 。
为了方便测试,下面给出基于 FileChannel 完成 channel-to-channel 的数据传输示例 。
推荐阅读
- 淘宝从百万到千万级并发的14次服务端架构演进之路
- 几百万扔进水?买二手房千万避开这几类房源
- 分布式、高并发、多线程,这些概念还傻傻分不清吗?
- Java 并发编程:如何保证共享变量的原子性?
- 硬核!如何模拟 5w+ 的并发用户?
- 格鲁吉亚中国茶王刘峻周诞辰150周年之际获百万赔偿
- 安徽省科技厅强化科技支撑推进精准扶贫
- PHP导出百万条数据方法
- 重金寻人 , 你是我们要找的百万英雄吗 内含福利
- 带你深入了解高并发架构
