Java中各种锁机制

1、公平锁/非公平锁

公平锁:
是指多个线程按照申请锁的顺序来获取锁,类似排队打饭,先到先得。
非公平锁:
是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁在高并发的情况下,有可能会造成优先级反转或者饥饿现象
代码中的应用:
并发包中ReentrantLock的创建可以指定构造函数的boolean类型来得到公平锁或非公平锁,默认是非公平锁

2、可重入锁(又名递归锁)

定义:
指的是同一个线程外层函数获得锁之后,内层递归函数仍然能获得该锁的代码,在同一个线程在外层方法获取锁的时候,在进入内层方法会自动回去锁

也即是说,线程可以进入任何一个它已经拥有的锁所同步着的代码块。

说人话:就是在一个同步方法里调用了另一个同步方法,这两个同步方法都是用的同一把锁,这样在里面的那个同步方法就也可以获得这把锁。
有点: 避免线程死锁
应用: ReentrantLock和Synchronize就是典型的可重入锁
测试代码:

/**
 * @author shihangqi
 * @date 2019/10/23 - 9:42
 *  运行结果
 *  11	  invoked sendSMS()              t1线程在外层方法获取锁的时候
 *  11	  ######invoked sendEmail()      t1在进入内层方法会自动获取锁
 *  12	  invoked sendSMS()
 *  12	  ######invoked sendEmail()
 */

class Pthone{

    public synchronized void sendSMS()throws Exception{
        System.out.println(Thread.currentThread().getId()+"\t invoked sendSMS()");
        sendEmail();//这里的线程也是sms中的线程
    }
    public synchronized void sendEmail()throws Exception{
        System.out.println(Thread.currentThread().getId()+"\t ######invoked sendEmail()");
    }
}


public class ReentrantLockDemo {

    public static void main(String[] args) {
        
        Pthone pthone = new Pthone();

        new Thread(()->{
            try {
                pthone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"t1").start();
        new Thread(()->{
            try {
                pthone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"t2").start();

    }


}

3、自旋锁

是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU

代码演示

/**
 * @author shihangqi
 * @date 2019/10/23 - 16:02
 *
 * 题目:实现一个自旋锁
 * 自旋锁的好处:循环比较获取知道成功为止,没有类似wait的阻塞
 *
 * 通过CAS操作完成自旋锁,A线程先进来调用myLock方法自己
 *
 */

public class SpinLockDemo {

    //原子引用线程
    AtomicReference<Thread> atomicReference = new AtomicReference<>();

    public void myLock(){
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"\t come in");
        while (!atomicReference.compareAndSet(null,thread)){

        }
    }

    public void myUnlock(){
        Thread thread = Thread.currentThread();
        atomicReference.compareAndSet(thread,null);
        System.out.println(Thread.currentThread().getName()+"\t invoked myUnLock");
    }

    public static void main(String[] args) {

        SpinLockDemo spinLockDemo = new SpinLockDemo();

        new Thread(()->{
            spinLockDemo.myLock();
            System.out.println(Thread.currentThread().getName()+"\t 在执行睡1秒");
            try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e){ e.printStackTrace(); }
            spinLockDemo.myUnlock();
        },"t1").start();
        
        
        try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e){ e.printStackTrace(); }
        
        new Thread(()->{
            spinLockDemo.myLock();
            System.out.println(Thread.currentThread().getName()+"\t 我终于可以执行了");
            spinLockDemo.myUnlock();
        },"t2").start();


    }
}

独占锁(写锁)/共享锁(读锁)/互斥锁

独占锁:指该锁一次只能被一个线程所持有。对ReentrantLock和Synchronized而言都是独占锁
共享锁:指该锁可以被多个线程所持有。
对ReentrantReadWriteLock其读锁是共享锁,写锁是独占锁。
实例代码:

class MyCache{
    private volatile Map<String,Object> map = new HashMap<>();
    private ReentrantReadWriteLock  rwLock = new ReentrantReadWriteLock();


    public void put(String key,Object vlaue){
        rwLock.writeLock().lock();
        try{
            System.out.println(Thread.currentThread().getName()+"\t正在写入:"+key);
            try { TimeUnit.MILLISECONDS.sleep(300); } catch (InterruptedException e){ e.printStackTrace(); }
            map.put(key, vlaue);
            System.out.println(Thread.currentThread().getName()+"\t写入完成:");
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            rwLock.writeLock().unlock();
        }

    }
    public void get(String key){
        rwLock.readLock().lock();
        try{
            System.out.println(Thread.currentThread().getName()+"\t正在读取:");

            try { TimeUnit.MILLISECONDS.sleep(300); } catch (InterruptedException e){ e.printStackTrace(); }
            Object result = map.get(key);
            System.out.println(Thread.currentThread().getName()+"\t读取完成:"+result);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            rwLock.readLock().unlock();
        }
    }
    public void clear(){
        map.clear();
    }

}


public class ReadWriteLockDemo {

    public static void main(String[] args) {
        MyCache myCache = new MyCache();

        for(int i = 1; i <= 5; i++){
            final  int tempInt = i;
            new Thread(()->{
                myCache.put(tempInt+"",tempInt+"");
            },String.valueOf(i)).start();
        }
        
        for(int i = 1; i <= 5; i++){
            final  int tempInt = i;
            new Thread(()->{
                myCache.get(tempInt+"");
            },String.valueOf(i)).start();
        }
    }


}

你可能感兴趣的:(面试集锦)