4_尚硅谷面试 第二季 -锁

公平锁 和 非公平锁
是什么
公平锁:
	是指多个线程按照申请锁的顺序来获取锁,类似排队打饭,先来后到
非公平锁:
	是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程先获取锁,
	在高并发的情况下,有可能造成优先级反转或者饥饿现象(线程一直获取不到锁)
对于 ReentrantLock而言,
通过构造函数指定该锁是否公平锁,默认非公平锁。非公平锁优点在于吞吐量比公平锁大
对于Synchronized而言,也是非公平锁
可重入锁(递归锁)
是什么
指的是同一个线程外层函数获得锁之后,内层递归函数仍能获取该锁的代码,在同一个
线程在外层方法获取锁的时候,在进入内层方法会自动获取锁
也即是说,线程可以进入任何一个他已经拥有的锁所同步着的代码块
作用
避免死锁
可重入锁(synchronized)
public class TestSynchronized {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() -> phone.sendEmail(),"t1").start();
        new Thread(() -> phone.sendEmail(),"t2").start();
    }
}

class Phone {
    public synchronized void sendEmail() {
        System.out.println(Thread.currentThread().getName() + "  sendEmail");
        senMsg();
    }
    public synchronized void senMsg() {
        System.out.println(Thread.currentThread().getName() + " senMsg ");
    }

}
/**
 * t1  sendEmail
 * t1 senMsg
 * t2  sendEmail
 * t2 senMsg
 */
可重入锁(synchronized)
public class TestReentrantLock {

    public static void main(String[] args) {
        Phone1 phone1 = new Phone1();
        Thread t1 = new Thread(phone1,"t1");
        Thread t2 = new Thread(phone1,"t2");
        t1.start();
        t2.start();
    }
}


class Phone1 implements Runnable {
    Lock lock = new ReentrantLock();
    public void sendEmail() {
        lock.lock(); //加几次 解几次 加多解少 死锁 加少解多 Exception in thread "t1" Exception in thread "t2" java.lang.IllegalMonitorStateException
        try {
            System.out.println(Thread.currentThread().getName() + "  sendEmail");
            senMsg();
        } finally {
//            lock.unlock();
            lock.unlock();
        }

    }

    public void senMsg() {
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " senMsg ");
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void run() {
        sendEmail();
    }
}
/**
 * t1  sendEmail
 * t1 senMsg
 * t2  sendEmail
 * t2 senMsg
 */
自旋锁
是什么
是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式尝试获取锁,这样的好处是减少线程切换的消耗,缺点是
循环会消耗CPU
实现自旋锁
public class SpinLock {
    public static void main(String[] args) throws InterruptedException {
        MyLock lock = new MyLock();
        new Thread(() -> {
            lock.lock();
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unLock();

        }, "t1 ").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(() -> {
            lock.lock();
            lock.unLock();
        }, "t2 ").start();

    }

}
class MyLock {

    AtomicReference<Thread> ref = new AtomicReference(); //引用类型默认为null

    public void lock() {
        Thread thread = Thread.currentThread(); //当前线程
        System.out.println(Thread.currentThread().getName() + "  come in");
        while (!ref.compareAndSet(null, thread)) { //要取反 

        }
    }

    public void unLock() {
        Thread thread = Thread.currentThread();//当前线程
        System.out.println(Thread.currentThread().getName() + "  come out");
        ref.compareAndSet(thread, null);
    }
}
/**
 * t1   come in
 * t2   come in
 * t1   come out
 * t2   come out
 */
独占锁和共享锁
独占锁
指该锁一次只能被一个线程持有。对ReentrantLock 和 synchronized 而言都是独占锁
共享锁
指该锁可以被多个线程所持有
对于ReentrantReadWriteLock 其读锁是共享锁,其写锁是独占锁
读锁的共享锁可以保证并发读是非常高效的,读写,写读,写写的过程是互斥的
演示问题
/**
 * 测试独占
 */
public class TestExclusive {
    public static void main(String[] args) {
        MyCache cache  = new MyCache() ;
        for (int i = 0; i < 5; i++) {
            final int num = i;
            new Thread(()->{
                cache.put(String.valueOf(num),num);
            },String.valueOf(num)).start();
        }

        for (int i = 0; i < 5; i++) {
            final int num = i;
            new Thread(()->{
                cache.get(String.valueOf(num));
            },String.valueOf(num)).start();
        }

    }
}

 class  MyCache{
    private volatile Map<String,Object> map = new HashMap<>();
    public void put(String key, Object value){
        System.out.println(Thread.currentThread().getName() + "  start put .....");
        map.put(key,value);
        System.out.println(Thread.currentThread().getName() + "  end put .....");
    }

     public void get(String key){
         System.out.println(Thread.currentThread().getName() + "  start get .....");
         Object result = map.get(key);
         System.out.println(Thread.currentThread().getName() + "   end  get....."  + result);
     }

 }
 /**

  3  start put .....
  4  start put .....
  4  end put .....
  2  start put .....
  0  start put .....
  0  end put .....
  1  start put .....
  2  end put .....
  3  end put .....
  1  end put .....
  0  start get .....
  1  start get .....
  0   end  get.....0
  2  start get .....
  1   end  get.....1
  4  start get .....
  3  start get .....
  2   end  get.....2
  3   end  get.....3
  4   end  get.....4

  */
解决问题
public class TestExclusive {
    public static void main(String[] args) {
        MyCache cache  = new MyCache() ;
        for (int i = 0; i < 5; i++) {
            final int num = i;
            new Thread(()->{
                cache.put(String.valueOf(num),num);
            },String.valueOf(num)).start();
        }

        for (int i = 0; i < 5; i++) {
            final int num = i;
            new Thread(()->{
                cache.get(String.valueOf(num));
            },String.valueOf(num)).start();
        }

    }
}

 class  MyCache{
    private volatile Map<String,Object> map = new HashMap<>();
    private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    public void put(String key, Object value){
        rwLock.writeLock().lock();
      try{
          System.out.println(Thread.currentThread().getName() + "  start put .....");
          map.put(key,value);
          System.out.println(Thread.currentThread().getName() + "  end put .....");
      }finally {
          rwLock.writeLock().unlock();
      }
    }

     public void get(String key){
         rwLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "  start get .....");
            Object result = map.get(key);
            System.out.println(Thread.currentThread().getName() + "   end  get....."  + result);
        }finally {
            rwLock.readLock().unlock();
        }
     }

 }
/**
 * 0  start put .....
 * 0  end put .....
 * 2  start put .....
 * 2  end put .....
 * 1  start put .....
 * 1  end put .....
 * 3  start put .....
 * 3  end put .....
 * 4  start put .....
 * 4  end put .....
 * 0  start get .....
 * 0   end  get.....0
 * 4  start get .....
 * 2  start get .....
 * 1  start get .....
 * 2   end  get.....2
 * 3  start get .....
 * 4   end  get.....4
 * 3   end  get.....3
 * 1   end  get.....1
 * */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值