背景
- 多线程一般有什么问题?那就是线程不安全。而如何保证线程安全呢?上锁
- 上锁也可以理解同步
- 用了锁又会产生什么问题?那就死锁或者严重影响性能
过程
- 同步问题核心三要素? 来源复建老师的Netty教学视频
- 原子性:“并无一气呵成,岂能无懈可击”
- 可见性:“你做的改变,别人看不见”。
- 有序性:“不按套路出牌”。比如指令重排序。i++之类的
- 锁的分类?
- 对竞争的态度:乐观锁(java.util.concurrent包中的原子类使用自旋锁CAS相关知识实现)与悲观锁(synchronized)。乐观锁提高程序性能。
- 等待锁的人是否公平而言:公平锁new ReentrantLock(true)和非公平锁 new ReentrantLock()。非公平锁效率是非常好的,吞吐量大。因为线程上下文切换的次数非常少。
- 是否可以共享:共享锁和独享锁:ReadWriteLock,其读锁是共享锁,其写锁是独享锁。目的:提高程序执行速度,使用共享锁提高性能。
- Netty是如何使用锁的? 实战中的使用。看看具体的代码逻辑是否是线程安全还是不安全的?都是读那就安全,如果存在写就有可能出现错误。
-
在意锁的对象和范围:减少粒度。(锁方法还是锁方法中的对象?)
-
注意锁的对象本身大小:减少空间占用。(引用类型和基本类型)AtomicLong转换成 long的应用。
-
注意锁的速度:提供并发性。(Netty根据JDK的变化而变化)
a) ConcurrentHashMapV8(以前的代码,现在已经没有这样的代码了) -
不同场景选择不同的并发包:因需而变。(多生产多消费 到 多生产单消费jctools的MPSC)
-
衡量好锁的价值:能不用则不用。
a) 多个服务员服务多个包厢。(比如要一碗饭,很可能会拿到两碗)b) 一个服务员服务多个包厢。(效率是比较高的)
c) NioEventLoopGroup(一个线程服务多个channel,一个channel中就是串行),两个EventLoopGroup是并行,一个EventLoopGroup对应多个Channel是并行。一个channel中是串行。整体并行,局部串行。
d) 避免用锁:用ThreadLocal来避免资源争用,Netty中轻量级的线程池实现,io.netty.util.Recycler#threadLocal
-
用锁的最高境界就是:不用锁也一样可以解决问题。
小结
- 并发编程中锁的一些基础知识。至少得有个理解。
- 用锁的最高境界就是:不用锁也一样可以解决问题。