-
Notifications
You must be signed in to change notification settings - Fork 780
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
2019-08-30:什么是悲观锁和乐观锁? #133
Comments
锁是为了避免自己在修改资源的时候,别人同时在修改,导致同一时间产生两份修改,不知道如何处理的情况而设置的独占资源,避免多个操作同时处理同一资源的技术。 乐观锁:默认为,某个线程在自己处理共享资源的时候,不会出现同一时刻来修改此资源的前提,只在处理完毕,最后写入内存的时候,检测是否此资源在之前未被修改。类似于读写锁的读锁就是乐观锁。 悲观锁:默认为,某个线程在自己处理共享资源的时候,一定会出现同一时刻来修改此资源,所以刚拿到这个资源就直接加锁,不让其他线程来操作,加锁在逻辑处理之前。类似,synchronized关键字,条件锁,数据库的行锁,表锁等就是悲观锁。 |
这次试试用故事解释一下: 总结:
推荐文章: |
乐观锁:认为并发修改的几率很小,在将修改的数据写进内存的时候判断当前资源之前是否被修改。 |
悲观锁:在每次线程对共享数据资源进行处理时,总是认为会出现并发修改,即有其他线程也在对此共享资源数据进行修改。每次在进行共享数据修改时要先获得相应的锁,才能对其进行修改。使用此种锁机制的时候,当一个线程在对共享数据行进修改时,其他线程都进入等待,只有通知当前运行完毕,其他线程需要通过不断地争夺执行权,等待,直到获取到执行权为止。 乐观锁:总是认为在进行共享资源数据改动时,不会出现有其他线程同时修改的情况,但是当存入内存,进行保存的时候,需要判断是否再保存数据之前对数据进行了修改。即当不同线程对数据进行修改时,可同时进行修改,但是保存时要改动相应的版本号,以证明此数据已被修改,如果在修改之前和修改之后的版本号不同时,则需要重新对数据进行修改,直到保存成功 |
锁:为了避免多个线程在同一时间修改同一公共数据时发生混乱 |
悲观锁 每次取的时候都会加锁 |
简单点来说 synchronized相当于就是悲观锁, 也就是你获取到锁的时候别人都不能操作,你释放锁之后别人才可以操作. |
#基本概念 乐观锁:乐观锁在操作数据时非常乐观,认为别人不会同时修改数据。因此乐观锁不会上锁,只是在执行更新的时候判断一下在此期间别人是否修改了数据:如果别人修改了数据则放弃操作,然后进行重试,否则执行操作。 悲观锁:悲观锁在操作数据时比较悲观,认为别人会同时修改数据。因此操作数据时直接把数据锁住,直到操作完成后才会释放锁;上锁期间其他人不能修改数据。 #实现方式 乐观锁的实现方式主要有两种:CAS机制和版本号机制 #优缺点和适用场景 例如,CAS只能保证单个变量操作的原子性,当涉及到多个变量时,CAS是无能为力的,而synchronized则可以通过对整个代码块加锁来处理。再比如版本号机制,如果query的时候是针对表1,而update的时候是针对表2,也很难通过简单的版本号来实现乐观锁。 2、竞争激烈程度 当竞争不激烈 (出现并发冲突的概率小)时,乐观锁更有优势,因为悲观锁会锁住代码块或数据,其他线程无法同时访问,影响并发,而且加锁和释放锁都需要消耗额外的资源。 #乐观锁加锁吗? (1)乐观锁本身是不加锁的,只是在更新时判断一下数据是否被其他线程更新了;AtomicInteger便是一个例子。 (2)有时乐观锁可能与加锁操作合作,例如,在前述updateCoins()的例子中,MySQL在执行update时会加排它锁。但这只是乐观锁与加锁操作合作的例子,不能改变“乐观锁本身不加锁”这一事实。 #CAS有哪些缺点 (1)线程1读取内存中数据为A; (2)线程2将该数据修改为B; (3)线程2将该数据修改为A; (4)线程1对数据进行CAS操作 在第(4)步中,由于内存中数据仍然为A,因此CAS操作成功,但实际上该数据已经被线程2修改过了。这就是ABA问题。 在AtomicInteger的例子中,ABA似乎没有什么危害。但是在某些场景下,ABA却会带来隐患,例如栈顶问题:一个栈的栈顶经过两次(或多次)变化又恢复了原值,但是栈可能已发生了变化。 对于ABA问题,比较有效的方案是引入版本号,内存中的值每发生一次变化,版本号都+1;在进行CAS操作时,不仅比较内存中的值,也会比较版本号,只有当二者都没有变化时,CAS才能执行成功。Java中的AtomicStampedReference类便是使用版本号来解决ABA问题的。 2、高竞争下的开销问题 3、功能限制 除此之外,CAS的实现需要硬件层面处理器的支持,在Java中普通用户无法直接使用,只能借助atomic包下的原子类使用,灵活性受到限制。 |
No description provided.
The text was updated successfully, but these errors were encountered: