悲观锁
悲观锁总是假设最坏的情况,认为共享资源每次被访问时都可能会出现问题,所以在每次获取资源时都会进行上锁,这样其他线程想拿到这个共享资源时就会阻塞直到锁被释放,也就是共
享资源一次只能给一个线程使用,其他线程会阻塞,用完后才把资源转给其他线程。
在java中例如synchronized锁和lock锁都是悲观锁
在高并发的情况下,激烈的锁竞争会造成线程阻塞。大量线程的阻塞会造成系统的上下文切换
从而增加系统性能的开销,并且悲观锁还可能会出现死锁的情况。
乐观锁
乐观锁他和悲观锁恰恰相反,他总是假设最好的情况,认为共享资源每被访问时都不会出现问题,线程可以不停地执行,无需加锁也无需等待。只有在提交时才会去验证共享资源是否被修改(具体方法可以使用版本号机制和CAS算法)
在高并发的情况下,乐观锁相比悲观锁来说不会存在锁竞争激烈的情况下,也就不会造成线程阻塞也没有死锁的问题,在性能上会更胜一筹。但是如果在冲突频繁的情况下也就是写的操作较多的情况下,会频繁失败和重试(悲观锁的开销是固定的),这样会非常影响性能,导致CPU飙升
理论上来说话:
悲观锁通常用于写操作较多的情况下(多写操作,竞争激烈)这样可以避免频繁失败和重试影响性能,悲观锁的开销是固定的。不过,如果乐观锁解决了频繁失败和重试这个问题的话(比如LongAdder
),也是可以考虑使用乐观锁的,要视实际情况而定。
乐观锁通常用于写操作比较少的情况下(多读场景,竞争较少)这样可以避免频繁加锁影响性能。