公平锁、非公平锁
公平锁 : 不允许插队,必须先来后到
非公平锁: 允许插队(默认都是非公平锁)
可重入锁
synchronized 这里是同一把锁
package com.liu.lock8.reentrantLock; public class Demo01 { public static void main(String[] args) { Phone phone = new Phone(); new Thread(()->{ phone.sendMsg(); },"A").start(); new Thread(()->{ phone.sendMsg(); },"B").start(); } } class Phone{ public synchronized void sendMsg() { System.out.println(Thread.currentThread().getName() + " => sendMsg()"); call(); // 这里也有锁 } public synchronized void call() { System.out.println(Thread.currentThread().getName() + " => call()"); } }
lock 这里是两把不同的锁
package com.liu.lock8.reentrantLock; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Demo02 { public static void main(String[] args) { Phone02 phone = new Phone02(); new Thread(()->{ phone.sendMsg(); },"A").start(); new Thread(()->{ phone.sendMsg(); },"B").start(); } } class Phone02{ Lock lock = new ReentrantLock(); public void sendMsg() { lock.lock(); // 一共有两把锁 // lock锁必须配对,否则会死锁 try { System.out.println(Thread.currentThread().getName() + " => sendMsg()"); call(); // 这里也有锁 } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void call() { lock.lock(); lock.lock(); try { System.out.println(Thread.currentThread().getName() + " => call()"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
可重入锁(递归锁)=> 可以递归调用和嵌套
自旋锁 spinlock
自己写一个自旋锁
package com.liu.lock8.spinlock; import java.util.concurrent.atomic.AtomicReference; /** * 自旋锁 */ public class SpinlockDemo { AtomicReference<Thread> atomicReference = new AtomicReference<>(); // 加锁 public void myLock() { Thread thread = Thread.currentThread(); System.out.println(Thread.currentThread().getName() + " ==> mylock"); // 自旋锁 while (!atomicReference.compareAndSet(null, thread)) { System.out.println(Thread.currentThread().getName() + "自旋中"); } } // 解锁 public void myUnLock() { Thread thread = Thread.currentThread(); System.out.println(Thread.currentThread().getName() + " ==> myUnlock"); atomicReference.compareAndSet(thread, null); } }
运行结果: 线程T1先获得自旋锁,T1进入休眠状态,之后线程T2获得自旋锁,而T2一直在自旋,直到T1休眠结束,释放锁,线程T2才停止自旋并解锁。
死锁
什么是死锁?
模拟死锁:
package com.liu.lock8.deadlock; import java.util.concurrent.TimeUnit; public class DeadLockDemo { public static void main(String[] args) { String lockA = "lockA"; String lockB = "lockB"; new Thread(new MyThread(lockA,lockB),"T1").start(); new Thread(new MyThread(lockB,lockA),"T2").start(); } } class MyThread implements Runnable { private String lockA; // 这里的锁指的是要锁定的资源类对象 private String lockB; public MyThread(String lockA, String lockB) { this.lockA = lockA; this.lockB = lockB; } @Override public void run() { synchronized (lockA) { System.out.println(Thread.currentThread().getName() + " lock: " + lockA +",try to get "+lockB); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lockB) { System.out.println(Thread.currentThread().getName() + "lock: " + lockB + ",try to get " + lockA); } } } }
运行结果: T1获取到了lockA,但是同时想要拿到lockB;
T2获取到了lockB,但是同时想要拿到lockA;
两个线程一直在等待对方释放锁,线程无法停止下来,于是便会导致死锁!
解决死锁办法 在IDEA终端上可以使用这些命令排查问题
面试: 工作中如何排查问题(死锁)