乐观锁和悲观锁是在处理并发访问时使用的两种不同的策略。
乐观锁的基本思想是假设冲突很少发生,每个线程在修改数据之前,先获取一个版本号或时间戳,并在更新时检查这个版本号或时间戳,以确保其他线程没有同时修改数据。
乐观锁适用于读操作频繁,写操作相对较少的场景。当冲突较少,且并发写入的概率较低时,乐观锁的性能可能更好。
悲观锁则是假设冲突经常发生,因此在访问共享资源之前,线程会先获取锁,确保其他线程无法同时访问相同的数据。这可能导致并发性降低,因为只有一个线程能够访问数据。
悲观锁适用于写操作较为频繁,且并发写入的概率较高的场景。悲观锁可以有效地避免多个线程同时修改相同数据的情况。
乐观锁和悲观锁还有个区别:乐观锁因为比较乐观,所以一般是先做业务逻辑操作,比如参数处理,内存中进行模型组装调整,然后再去更新数据库。悲观锁因为比较悲观,所以会先尝试加锁,然后再去做业务逻辑操作。
也就是说,乐观锁是先干活,后加锁。悲观锁是先加锁,再干活。
而高并发的写操作时,你干了一大堆活,把模型都组装好了,内存计算也都做完了,结果最后去数据库那更新的时候发现版本号变了。这不是大冤种吗?
所以,应该是先尝试获取锁,如果获取锁成功,再进行业务操作,否则就直接返回失败。这样可以做fail-fast。
综上,在高并发场景中,一般来说并发写入的冲突较为频繁,所以建议优先考虑悲观锁。即在做并发操作前,先尝试获取锁,如果获取锁成功,在进行业务操作,否则就直接返回失败。
比如,我们通常在并发场景下都使用分布式锁,即先加分布式锁,然后再操作。这个就是一个悲观锁的思想,我认为冲突一定很大,所以我先尝试加锁。拿到锁再开始干活。
不管是乐观锁还是悲观锁,都并不是无锁的。这一点一定要注意。