1、synchronized 和 lock 的区别:
1、synchronized 是java中的一个关键字,而Lock是一个接口
2、synchronized 的作用域是:1、用在某一个对象上—> synchronized(this)
2、用在方法上—> public synchronized void run(){}
3、用在类上 —> synchronized(SynchronizedDemo.class){} 、 public synchronized static void method(){}
3、lock 只能给方法上锁 ***注意:Lock 要定义成static静态的全局变量,不能定义在方法里面
4、synchronized 不需要手动获取锁和释放锁,不会造成死锁 ;lock需要自己加锁和释放锁,如果没有unLock()释放锁会造成死锁;
2、synchronized 的四种状态:无锁 偏向锁 轻量锁 重量锁
如果只有A线程执行,则会变成偏向锁,单单偏向A线程。下次A线程再进来就能直接进来,不需要额外的cas操作。如果B线程进来,发现当前锁偏向A线程,就会通过cas竞争锁,竞争失败说明有多个线程竞争,就会再安全点的时候将锁升级为轻量级锁。如果轻量级锁还存在锁竞争失败的情况,就会升级为重量级锁,再竞争激烈的情况下,重量级锁会比轻量级锁更高的性能。
3、CAS算法:CAS(Compare And Swap/Set)比较并交换,CAS 算法的过程是这样:它包含 3 个参数 CAS(V,E,N)。V 表示要更新的变量(内存值),E 表示预期值(旧的),N 表示新值。当且仅当 V 值等 于 E 值时,才会将 V 的值设为 N,如果 V 值和 E 值不同,则说明已经有其他线程做了更新,则当 前线程什么都不做。最后,CAS 返回当前 V 的真实值。CAS 操作是抱着乐观的态度进行的(乐观锁),它总是认为自己可以成功完成操作。当多个线程同时 使用 CAS 操作一个变量时,只有一个会胜出,并成功更新,其余均会失败。失败的线程不会被挂 起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作。基于这样的原理, CAS 操作即使没有锁,也可以发现其他线程对当前线程的干扰,并进行恰当的处理。
4、synchronized 和ReentrantLock相比,局限性
1、synchronized加锁的时候不能设置超时时间。ReentrantLock可以提供tryLock方法设置超时时间
2、ReentrantLock可以使用多个Condition,而synchronized却只能有1个
3、ReentrantLock可以选择公平锁和非公平锁
4、ReenTrantLock可以获得正在等待线程的个数,计数器等
5、关于synchronized与lock的性能比较
性能:在高并发的情况下都是在一个数量集的,较高和较低并发下,synchronized都比Lock来的快,基本是两倍的关系。到底是使用synchronized还是使用lock!我们写同步的时候,优先考虑synchronized,如果有特殊需要,再进一步优化,可以考虑使用lock。
synchronized使用场景1:
假设用户手速很快,极短时间内点了两次领奖按钮(前端没有进行控制,我们也不能依赖前端去控制)。那么可能掉了两次领奖接口,而且有可能第二次调用的时候查询数据库的时候,第一次领奖还没有执行完成更新领奖标记。
package com.nx.vip.p6.lock;
public class SynTest {
public static void main(String[] args) {
SynTest synTest = new SynTest();
synTest.test();
}
public void test(){
new SynThreadle().start();
new SynThreadle().start();
}
public void syn(String userName) throws InterruptedException {
synchronized (userName){
System.out.println("进入到同步块"+userName);
Thread.sleep(5000);
System.out.println("退出同步块"+userName);
}
}
class SynThreadle extends Thread{
public void run(){
try {
syn("111");
}catch (Exception e){
e.printStackTrace();
}
}
}
}
结果:
进入到同步块111
退出同步块111
进入到同步块111
退出同步块111