上海的网站设计公司价格,做电商与做网站的区别,花生壳怎么发布自己做的网站,买域名的网站threadsafe这篇博客文章通过说明我们如何轻松访问线程内存来进行线程安全操作#xff0c;继续了我在Agrona库上进行的系列文章 。 在继续讨论这是一个相当高级的主题之前#xff0c;我可能应该警告一下#xff0c;并且我不尝试解释诸如内存屏障之类的概念#xff0c;仅概述… threadsafe 这篇博客文章通过说明我们如何轻松访问线程内存来进行线程安全操作继续了我在Agrona库上进行的系列文章 。 在继续讨论这是一个相当高级的主题之前我可能应该警告一下并且我不尝试解释诸如内存屏障之类的概念仅概述API的功能。 ByteBuffer的不足 Java提供了一个字节缓冲区类来包装offheap和onheap内存。 字节缓冲区在Java网络堆栈中专门用作从中读取或写入数据的位置。 那么字节缓冲区有什么问题呢 好吧因为它们针对用例所以它们不提供对原子操作之类的支持。 如果要编写可从不同进程同时访问的非堆数据结构则字节缓冲区无法满足您的需求。 您可能要编写的那种库的一个示例是一个消息队列一个进程将读取该消息而另一个进程将写入该消息队列。 Agrona的缓冲器 Agrona提供了几种缓冲区类和接口来克服这些缺陷。 Aeron和SBE库都使用这些缓冲区。 DirectBuffer –顶级接口可从缓冲区读取值。 MutableDirectBuffer –扩展DirectBuffer添加操作以写入缓冲区。 AtomicBuffer –不它不是核动力的MutableDirectBuffer 该接口添加了原子操作以及比较和交换语义。 UnsafeBuffer –默认实现。 名称unsafe并不意味着不应该使用该类只是其支持实现使用sun.misc.Unsafe 。 拆分缓冲区而不是分配单个类的决定是出于希望限制不同系统组件对缓冲区的访问权限的考虑。 如果一个类只需要从一个缓冲区中读取则不应允许它通过使缓冲区发生突变而将错误引入系统。 同样不允许设计为单线程的组件使用Atomic操作。 包装一些内存 为了能够使用缓冲区执行任何操作您需要告诉它缓冲区的起始位置 此过程称为包装基础内存。 所有包装内存的方法都称为wrap并且可以包装byte[] ByteBuffer或DirectBuffer 。 您还可以指定用于包装数据结构的偏移量和长度。 例如这里是包装byte[] 。 final int offset 0;final int length 5;buffer.wrap(new byte[length], offset, length); 包装还有另一个选择–这是存储位置的地址。 在这种情况下该方法采用存储器的基地址及其长度。 这是为了支持诸如通过sun.misc.Unsafe分配的内存或例如malloc调用之类的事情。 这是使用Unsafe的示例。 final int length 10;final long address unsafe.allocateMemory(length);buffer.wrap(address, length); 包装内存还可以设置缓冲区的容量可以通过capacity()方法进行访问。 存取器 因此现在您有了可以读取和写入的堆外内存缓冲区。 约定是每个getter以单词get开头并以您要获取的值的类型作为后缀。 您需要提供一个地址以说出要读取的缓冲区中的位置。 还有一个可选的字节顺序参数。 如果未指定字节顺序则将使用计算机的本机顺序。 这是一个有关如何在缓冲区开始处加长的示例 final int address 0;long value buffer.getLong(address, ByteOrder.BIG_ENDIAN);value;buffer.putLong(address, value, ByteOrder.BIG_ENDIAN); 除基本类型外还可以从缓冲区中获取和放入字节。 在这种情况下要读取或读取的缓冲区作为参数传递。 再次支持byte[] ByteBuffer或DirectBuffer 。 例如这是将数据读入byte[] 。 final int offsetInBuffer 0;final int offsetInResult 0;final int length 5;final byte[] result new byte[length];buffer.getBytes(offsetInBuffer, result, offsetInResult, length, result);并发操作 int和long值也可以使用内存排序语义进行读取或写入。 后缀为Ordered方法保证它们最终将被设置为所讨论的值并且该值最终将在另一个对该值进行易失性读取的线程中可见。 换句话说 putLongOrdered自动执行存储存储内存屏障 。 get*Volatile和put*Volatile遵循与在Java中用volatile关键字声明的变量的读写相同的排序语义。 也可以通过AtomicBuffer更复杂的内存操作。 例如有一个compareAndSetLong 它将在给定的索引上原子地设置一个更新的值给定的现有值是一个期望值。 getAndAddLong方法是在给定索引处添加的完全原子的方法。 生活中没有什么是免费的所有这些都需要警告。 如果您的索引词不对齐这些保证将不存在。 请记住它也有可能撕裂一些薄弱内存体系结构如ARM和Sparc过字边界写入值看到堆栈溢出对这种事情的更多细节。 边界检查 边界检查是棘手的问题之一也是正在进行的辩论的主题。 避免边界检查可以提高代码速度但会带来导致段错误并降低JVM的潜力。 Agrona的缓冲区使您可以选择通过命令行属性agrona.disable.bounds.checks禁用边界检查但默认情况下是边界检查。 这意味着它们的使用是安全的但是如果对经过测试的代码进行应用程序性能分析确定范围检查是瓶颈则可以将其删除。 结论 Agrona的缓冲区使我们可以轻松使用offheap内存而不受Java现有字节缓冲区强加给我们的限制。 我们正在继续扩展可从maven central下载的库。 感谢Mike BarkerAlex WilsonBenji WeberEuan Macgregor和Matthew Cranman对本文的帮助。 翻译自: https://www.javacodegeeks.com/2015/08/agronas-threadsafe-offheap-buffers.htmlthreadsafe