在程序开发中,我们经常用多线程技术来提高程序的工作效率,但是高并发的场景下,多线程会存在线程安全问题,用锁来解决。
内容一览:
Netty 玩转锁的五个关键点
例:初始化 channel (io.netty.bootstrap.ServerBootstrap#init)
Synchronized method -> Synchronized block
void init(Channel channel) throws Exception { Map<ChannelOption<?>, Object> options = this.options0(); synchronized(options) { setChannelOptions(channel, options, logger); } Map<AttributeKey<?>, Object> attrs = this.attrs0(); synchronized(attrs) { Iterator var5 = attrs.entrySet().iterator(); while(true) { if (!var5.hasNext()) { break; } Entry<AttributeKey<?>, Object> e = (Entry)var5.next(); AttributeKey<Object> key = (AttributeKey)e.getKey(); channel.attr(key).set(e.getValue()); } } //... }
例:统计待发送的字节数 (io.netty.channel.ChannelOutboundBuffer)
AtomicLong -> Volatile long + AtomicLongFieldUpdater
前者是一个对象,包含对象头(object header)以用来保存 hashcode、lock等信息,32 位系统占用 8 字节,64 位系统占用 16 字节,所以在 64 位系统下:
至少节约 24 字节!
结论:Atomic objects -> Volatile primary type + static Atomic FieldUpdater
原子类型的对象可以用 volatile 修饰的基础类型来代替,以节省空间
例1:记录内存分配字节数等功能用到的 LongCounter (io.netty.util.internal.PlatformDependent#newLongCounter())
高并发时:java.util.concurrent.atomic.AtomicLong -> java.util.concurrent.atomic.LongAdder (JDK)
结论:及时衡量,使用jdk最新功能
例2:曾经根据不同情况,选择不同的并发包实现:JDK < 1.8 考虑 ConcurrentHashMapV8(ConcurrentHashMap 在 JDK8 中的版本)
例1:关闭和等待关闭事件执行器(Event Executor):
Object.wait/notify -> CountDownLatch
io.netty.util.concurrent.SingleThreadEventExecutor#threadLock
例2:Nio Event Loop 中负责存储 task 的 Queue
Jdk's LinkedBlockingQueue(MPMC) -> jctools' MPSC
MPMC: muti-producer & muti-consumer
io.netty.util.internal.PlatformDependent.Mpsc#newMpscQueue(int)
生活场景:
饭店提供了很多包厢,服务模式:
表面上看,前者效率没有后者高,但实际上它避免了服务员间的沟通(上下文切换)等开销,避免客人与服务员之间导出乱串,管理简单。
局部串行:Channel 的 I/O 请求处理 Pipeline 是串行的
整体并行:多个串行化线程(Nio Event Loop)
Netty 应用场景下:局部串行 + 整体并行 > 一个队列 + 多个线程模式:
本文由博客一文多发平台 OpenWrite 发布!