面试中常问的锁你都知道吗?

(1)乐观锁VS悲观锁
1》乐观锁

他认为一般情况下不会出现问题,所有他在使用的时候不会加锁,只有在数据修改的时候才会判断有没有锁竞争,如果没有就会直接修改数据,如果有则会返回失败信息给用户自行处理。
乐观锁的经典事项:CAS(Compare And Swap)对比并且替换

  • 1)CAS实现

(V【内存中的值】,A【预期的旧值】,B【新值】)
每次把V和A进行对比,如果V==A则将V修改为B,如果不相等,则不修改。进行自旋对比和替换。

  • 2)CAS实现原理是什么?
public final native boolean compareAndSwapObject(Object var1,long var2,Object var3)

CAS在java中是通过UnSafe实现,UnSafe是本地类和本地方法,它是C/C++实现的原生方法,通过调用操作系统的Atomic::cmpxchg(原子指令)来实现的。

  • 3)CAS的应用:Atomic*
private  static AtomicInteger count = new AtomicInteger(0);
  • 4)在多线程中实现i++,i–保证线程安全的方法:

1.加锁
2.ThreadLocal
3.AtomicInteger

  • 5)CAS(乐观锁)存在的问题:ABA问题
  • ABA问题:

(1)在我给别人转账100元的情况下点击了两次提交的按钮(V=100,A=100,B=0)
第一次提交时V=100,A=100,V=A则V=B=0; 第二次提交时V=0,A=100 ,V!=A,停止执行,这种情况下是正常的。
(2)但是当我在第二次提交的时候,有人在我第二次提交前给我也转了100元。 第一次提交V=100,A=100,V=A则V=B=0;
在中间是别人给我转钱V=100 第二次提交V=100,A=100,则V==A,V=B=0,此时又进行了一次转账。
这个就是ABA问题在经历了一段时间一定事件后A又变成A。

  • 6)如何解决ABA问题?

使用版本号(AtomicStampedReference),每次修改的时候判断预期的旧值和版本号,每次成功修改之后更换版本号,这样即使预期的值和V值相等,但是因为版本号不同,也不能进行修改,从而解决了ABA问题。

private  static AtomicStampedReference money = new AtomicStampedReference(100,1);
    public static void main(String[] args) throws InterruptedException {
        //两次转账
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
               boolean resule1= money.compareAndSet(100,0,1,2);//旧值,新值,旧版本号,新版本号
                System.out.println(resule1);//true
            }
        });
        thread.start();
        //增加100
        Thread thread3= new Thread(new Runnable() {
            @Override
            public void run() {
                boolean resule2= money.compareAndSet(0,100,2,3);
                System.out.println(resule2);//true
            }
        });
        thread3.start();
        thread.join();
        thread3.join();
        Thread thread2= new Thread(new Runnable() {
            @Override
            public void run() {
                boolean resule2= money.compareAndSet(100,0,1,2);
                System.out.println(resule2);//false
            }
        });
        thread2.start();
        thread2.join();

    }

注意事项:AtomicReference有ABA问题AtomicStampedReference是解决ABA问题的.AtomicStampedReference它对比里面的旧值对比的是引用。
这里就有一个高速缓存机制,当取的值是范围里面的时,会直接按值对比,超过此范围就会对比地址。Integer(-128–127)

2》悲观锁

悲观锁是认为只要执行多线程就会出现问题,所以在进入方法后都会进行加锁。 悲观锁的实现就是synchronize。

2)公平锁VS非公平锁:

公平锁:1;一个线程释放锁,2;主动唤醒需要得到锁的线程。
非公平锁:抢占式执行,当一个线程释放锁,另一个线程刚好执行到获取锁的代码就可以获取到锁。 使用new
ReentrantLock(true)来设置公平锁,默认是false,非公平锁,synchronize是非公平锁

3)独占锁VS共享锁

独占锁:指的是这一把锁只能被这一个线程拥有。(synchronize)
共享锁:指的是这把锁可以被多个线程同时拥有。(ReadWriteLock中的读锁就是共享锁)将锁的粒度更加细化,从而提高锁的性能。

(4)可重入锁

一个线程在拥有了一把锁后,可以重复的进入(synchronize,ReentrantLock)

private  static  Object object = new Object();

    public static void main(String[] args) {
        synchronized (object){
            System.out.println("进入主方法");
            synchronized (object){
                System.out.println("重复进入方法");
            }
        }
    }

5)自旋锁

相当于死循环,一直循环尝试获取锁(synchronize)

6)偏向锁

在线程初次访问的时候,将线程的ID放入对象头偏向锁ID的字段中,每次线程访问的时候先判断线程的ID是否等于对象投中的ID,如果相等则说明这个线程用于此锁就可以正常执行代码,否则表明线程不拥有此锁,只能通过自旋的方式尝试

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值