堆外并发计数器

并发计数器几乎是每个系统的一部分,用于收集数据,线程同步等。Java对基于堆的计数器有很好的支持。

当您需要可以在处理器之间共享的计数器时,可能会有用例。

如何建立进程间计数器

数据库

这是我想到的第一个选项,数据库序列是可以被多个进程使用的计数器。 所有并发都由数据库处理。 对于初学者来说这是一个不错的选择,但我们知道您从数据库中获得的间接费用类型(网络,锁等)。 只有拉里·埃利西恩(Larry Elision)对此会感到高兴,而不是您!

一些服务器

您可以开发一些提供此类服务的服务器/中间件。 此选项仍将具有网络延迟,编组/非编组开销。

内存映射文件

您可以使用内存映射文件来执行此操作。 通过查看PeterLawrey 的Java中的线程安全进程间共享内存,我有了主意。

多进程计数器涉及的挑战。

数据可视性

一个过程完成的更改应该对所有过程可见。 通过使用内存映射文件可以解决此问题。 操作系统对此提供了保证,并且Java内存模型支持它使成为可能。

线程安全

计数器是关于多个作者的,因此线程安全成为一个大问题。 比较和交换是处理多个编写器的一种选择。 是否可以将CAS用于堆外操作? 是的,有可能这样做,欢迎来到Unsafe。 通过使用Memorymapped&Unsafe,可以将CAS用于非堆操作。

在此博客中,我将分享使用CAS映射内存的实验。

怎么样?

如何获得内存地址

MappedByteBuffer使用DirectByteBuffer,这是堆内存不足。 因此,可以获取内存的虚拟地址并使用不安全的方法来执行CAS操作。 让我们看一下代码。

FileChannel fc = new RandomAccessFile(fileName, "rw").getChannel();
// Map 8 bytes for long value.
mem = fc.map(FileChannel.MapMode.READ_WRITE, 0, 8);
startAddress = ((DirectBuffer) mem).address();

上面的代码创建8字节的内存映射文件并获取虚拟地址。 该地址可用于读取/写入内存映射文件的内容。

如何以线程安全的方式写/读
public boolean increment() {
		long orignalValue = readVolatile(startAddress);
		long value = convert(orignalValue);
		return UnsafeUtils.unsafe.compareAndSwapLong(null, 
				startAddress,orignalValue, convert(value + 1));
	}

	public long get() {
		long orignalValue = readVolatile(startAddress);
		return convert(orignalValue);
	}

	// Only unaligned is implemented
	private static long readVolatile(long position) {
		if (UnsafeUtils.unaligned()) {
			return UnsafeUtils.unsafe.getLongVolatile(null, position);
		}
		throw new UnsupportedOperationException();
	}

	private static long convert(long a) {
		if (UnsafeUtils.unaligned()) {
			return (UnsafeUtils.nativeByteOrder ? a : Long.reverseBytes(a));
		}
		throw new UnsupportedOperationException();
	}

要查看的重要功能是readVolatile增量 readVolatile直接从内存读取, 增量使用不安全的方法对从MemoryByteBuffer获得的地址执行CAS。

性能

我系统上的一些性能数字。 每个线程将计数器增加一百万次。

计数器+统计

计数器的性能很好,随着线程数量的增加,CAS故障开始发生并且性能开始下降。 这些计数器的性能可以通过具有多个段来减少写争用来提高。 我将在下一个博客中写它。

结论

  • 内存映射文件非常强大,可用于开发很多东西,例如堆外集合,IPC,堆外线程协调等。
  • 内存映射文件为GC较少编程打开了大门。

该博客中使用的所有代码都可以在github上找到

翻译自: https://www.javacodegeeks.com/2014/03/off-heap-concurrent-counter.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值