笔记D《公平锁非公平锁可重入锁递归锁自旋锁》

    技术2024-03-13  84

    文章目录

    公平锁 & 非公平锁可重入锁(递归锁)自旋锁独占锁 & 共享锁

    公平锁 & 非公平锁

    公平锁 公平锁是指多个线程按照申请锁的顺序来获取,先来先得。

    在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列。如果为空,或者当前线程是等待队列的第一个,就占有锁,佛则就加入到等待队列中,按照 FIFO 的规则取出。

    非公平锁 非公平锁是指在多线程获取锁的顺序并不是按照申请锁的顺序,而是一种抢占式的方式来获取锁。

    synchronized,ReentrantLock 都是一种非公平锁。 但是ReentrantLock的创建可以指定构造函数的boolean类型来得到公平锁或者非公平锁 默认是非公平锁。

    可重入锁(递归锁)

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

    也就是说:线程可以进入到任何一个它已经拥有锁同步的代码块中。

    作用:最大作用就是防止死锁,因为多层嵌套的锁,其实锁的是同一个对象,另一个含义就是:嵌套方法持有的是【同一把锁】。

    演示 synchronized 可重入锁 public class ReentrantLockDemo { private int x = 1; public static void main(String[] args) { ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo(); for(int i = 0;i<30;i++) { new Thread(() -> { reentrantLockDemo.set(); }, "t1").start(); } } public synchronized void set(){ // 获取锁 x = x+1; get(); } public synchronized void get(){ System.out.println(x); } } 演示 ReentrantLock 可重入锁 public class ReentrantLockDemo { public static void main(String[] args) { Phone phone = new Phone(); Thread t3 = new Thread(phone); Thread t4 = new Thread(phone); t3.start(); t4.start(); } } class Phone implements Runnable{ private Lock lock = new ReentrantLock(); @Override public void run() { get(); } private void get() { lock.lock(); try { System.out.println(Thread.currentThread().getName() + "\t" + "get"); set(); }finally { lock.unlock(); } } private void set() { lock.lock(); try{ System.out.println(Thread.currentThread().getName() + "\tset"); }finally { lock.unlock(); } } }

    自旋锁

    自旋锁是指尝试获取锁的线程不会立即阻塞,而是 采用循环的方式尝试获取锁,这样的好处是可以减少线程上下文切换,但是自循环会导致消耗 CPU 资源。

    public class SpinLockDemo { // 原子对象 AtomicReference<Thread> atomicReference = new AtomicReference<>(); public void myLock(){ Thread thread = Thread.currentThread(); System.out.println(thread.getName() + "\t"+" come"); 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(); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } },"AA").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(()->{ spinLockDemo.myUnLock(); },"BB").start(); } }

    独占锁 & 共享锁

    独占锁:锁每次只能被一个线程所持。synchronized,ReentrantLock 都是独占锁。

    共享锁:锁可以被多个线程所有,ReentrantReadWriteLock 的【读锁是共享锁,写锁是独占锁。】

    public class ReentrantLockDemo { public static void main(String[] args) { MyCache myCache = new MyCache(); for(int i= 1; i<=5;i++){ final int tmpInt = i; new Thread(()->{ myCache.put(tmpInt+"",tmpInt+""); },i+"").start(); } for(int i=1;i<=5;i++){ final int tempInt = i; new Thread(()->{ myCache.get(tempInt+""); },String.valueOf(i)).start(); } } } class MyCache{ private volatile Map<String,Object> map = new HashMap(); private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void put(String key,Object value){ lock.writeLock().lock(); System.out.println(Thread.currentThread().getName()+"\t"+"正在写入"); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } try { map.put(key, value); System.out.println(Thread.currentThread().getName() + "\t" + "写入完成"); }finally { lock.writeLock().unlock(); } } public void get(String key){ lock.readLock().lock(); System.out.println(Thread.currentThread().getName()+"\t 正在读取:"+key); try { TimeUnit.MILLISECONDS.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } try { Object result = map.get(key); System.out.println(Thread.currentThread().getName() + "\t 读取完成" + "\t" + result); }finally { lock.readLock().unlock(); } } }
    Processed: 0.018, SQL: 9