- 怎么降低锁竞争
减少锁的持有时间: 尽量缩短线程持有锁的时间,只在必要时才获取锁,一旦操作完成立即释放锁。可以通过将同步代码块的范围缩小到最小必要程度来实现,避免在锁保护的代码块中执行耗时操作或等待操作,比如I/O操作。
降低锁的粒度: 将大对象或大范围的锁拆分为多个小对象或小范围的锁,即锁分段技术。例如,ConcurrentHashMap就采用了分段锁,将整个哈希表分割成多个段,每个段都有自己的锁,这样多个线程可以同时访问不同段的数据,减少了锁的竞争。
使用乐观锁与悲观锁: 乐观锁通过版本号或时间戳的方式减少锁的直接竞争,只有在更新数据时检查数据是否被其他线程修改过,如果未修改则更新成功,否则重试。悲观锁则假设最坏情况,总是加锁,相比之下,乐观锁可以减少不必要的锁等待时间。
使用非阻塞数据结构与算法: 例如java.util.concurrent包下的ConcurrentLinkedQueue、AtomicInteger等,这些类使用了CAS(Compare and Swap)等无锁算法,可以在不使用传统锁的情况下保证线程安全,从而避免了锁竞争。
锁粗化与锁消除: 锁粗化是指将多个连续的加锁操作合并为一个更宽的锁范围,减少锁的获取与释放次数。锁消除是JVM层面的优化,它能够在运行时分析代码,如果发现某些锁对象不可能被其他线程访问,则可以消除这些锁操作,减少不必要的竞争。
使用读写锁: ReadWriteLock允许多个读取者同时访问共享资源,但只允许一个写入者。当读操作远多于写操作时,读写锁可以显著提高并发性能,因为读操作之间不会相互阻塞。
并发容器: 利用ConcurrentHashMap、CopyOnWriteArrayList等并发容器,它们内部实现了高效的线程安全机制,减少了对外部显式锁的依赖。
条件判断与循环优化: 在使用循环等待锁或其他资源时,加入适当的条件判断以避免无休止的空等待,比如使用while循环而非if判断结合wait/notify机制。
如果大家需要视频版本的讲解,欢迎关注我的B站: