java面试-公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解
一、公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解
公平锁:多个线程按照申请的顺序来获取锁。
非公平锁:多个线程获取锁的先后顺序与申请锁的顺序无关。【ReentrantLock 默认非公平、synchronized】
总结:非公平锁的吞吐量比公平锁大。
可重入锁(又名递归锁):线程可以进入任何一个它已经获取锁的同步代码块中。
可重入锁的最大作用:避免死锁
自旋转:是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁。
好处:减少线程上下文切换的消耗,
缺点:循环会消耗CPU
二、请手写一个自旋锁
/** * Created by wujuhong on 2019/1/14. * 通过AtomicReference可实现简单的自旋 */ public class SpinLock { //原子引用线程 private AtomicReference<Thread> atomicReference = new AtomicReference<>(); //让当前想要获取锁的线程做几个空循环 public void mylock() { Thread currentThread = Thread.currentThread(); System.out.println(Thread.currentThread().getName()+" come in"); while (!atomicReference.compareAndSet(null, currentThread)) { } } public void myunlock() { Thread currentThread = Thread.currentThread(); atomicReference.compareAndSet(currentThread, null); System.out.println(Thread.currentThread().getName()+" invoked myunlock"); } public static void main(String[] args) { SpinLock spinLock = new SpinLock(); new Thread(() -> { spinLock.mylock(); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } spinLock.myunlock(); },"AA").start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(() -> { spinLock.mylock(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } spinLock.myunlock(); },"BB").start(); } }
三、ReentrantReadWriteLock读写锁
- 允许多个线程同时读共享变量
- 只允许一个线程写共享变量
- 如果一个写线程正在执行写操作,此时禁止读线程读共享变量
说明:锁升级不允许,锁降级允许
public class ReadWriteLockDemo { //写操作:原子+独占,整个过程必须是一个完整的统一体,中间不许被分割,被打断。 public static void main(String[] args) { MyCache myCache = new MyCache(); for (int i = 0; i <= 5; i++) { final int tempInt = i; new Thread(() -> myCache.put(tempInt + "", tempInt), String.valueOf(i)).start(); } for (int i = 0; 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 rwlock = new ReentrantReadWriteLock(); public void put(String key, Object value) { rwlock.writeLock().lock(); try { System.out.println(Thread.currentThread().getName() + " 正在写入" + key); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } map.put(key, value); System.out.println(Thread.currentThread().getName() + " 写入完成"); } finally { rwlock.writeLock().unlock(); } } public void get(String key) { rwlock.readLock().lock(); try { System.out.println(Thread.currentThread().getName() + " 正在读取"); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } Object result = map.get(key); System.out.println(Thread.currentThread().getName() + " 读取完成" + result); } finally { rwlock.readLock().unlock(); } } }