同步锁,乐观锁,悲观锁
Synchronized
所有对象都自动含有单一的锁(监视器),当在对象上调用其任意
synchronized
方法的时候,此对象都被加锁。对于某个特定对象来说,其所有synchronized方法共享同一个锁
,这可以被用来防止多个任务同时访问被编码为对象内存。
对于同步方法,锁是当前实例对象。
public synchronized void test(int n);
同一时刻对于每一个类实例,其所有声明为
synchronized
的成员函数中至多只有一个处于可执行状态对于静态同步方法,锁是当前对象的
Class
对象。public static synchronized void test(int n);
对于同步方法块,锁是
Synchonized
括号里配置的对象。synchronized(SyncObject.Class) { //允许访问控制的代码 } or synchronized(this) { //允许访问控制的代码 }
代码必须获得对象 syncObject (类实例或类)的锁方能执行
悲观锁
悲观,则会假设情况总是最坏的,即共同维护的数据总会被其他线程修改,所以每次取数据的时候都会上锁,避免其他人修改。
synchronized
关键字的实现也是悲观锁。悲观锁的缺点
在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题。
一个线程持有锁会导致其它所有需要此锁的线程挂起。
如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险。
乐观锁
乐观,则假设情况总是最好的,即共同维护的数据不会被其他线程修改,所以不会上锁(即无锁)。
CAS(Compare and Swap)
非阻塞性,不存在死锁问题。没有锁竞争带来的系统开销,也没有线程间频繁调度带来的开销,具有更优越的性能。
算法过程
包含三个参数
CVS(V,E,N)
。V
表示要更新的变量,E
表示预期值,N
表示新值。仅当V
值等于E
值时,才会将V
的值设为N
,如果V
值与E
值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。
最后,CAS
返回当前V
的真实值。当多个线程同时使用CAS
操作一个变量时,只有一个会胜出,并成功更新,其余均会失败。
失败的线程不会挂起而是允许再次尝试。硬件层面,大部分处理器已经支持原子化的
CAS
指令。