一,公平锁和非公平锁
公平锁:先来先执行,不能插队
非公平锁:可以插队,默认是非公平锁
public ReentrantLock() { sync = new NonfairSync(); } public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
二,可重入锁(递归锁)
拿到外层的锁就会自动获取里面的锁
代码示例:
/** * 由于synchronized 是可重入锁,所以call的锁和sms的锁是同时拿到的 * 因此在A线程执行完sms方法时,B线程是无法执行sms方法的,需要等到A线程一起释放锁 */ public static void main(String[] args) { Phones phone = new Phones(); new Thread(()-> { phone.call(); },"A").start(); new Thread(()-> { phone.sms(); },"B").start(); } class Phones { public synchronized void call() { sms(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+": call"); } public synchronized void sms() { System.out.println(Thread.currentThread().getName()+":sms"); } }
执行结果
A:sms
A: call
B:sms
三,自旋转锁
会不断的去尝试,直到成功为止,会使用到while循环
@HotSpotIntrinsicCandidate public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); } while (!weakCompareAndSetInt(o, offset, v, v + delta)); return v; }
自定义自旋锁
import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; public class MyLock { AtomicReference<Thread> atomicReference = new AtomicReference<>(); public void lock() { Thread thread = Thread.currentThread(); System.out.println(thread.getName()+"尝试获取锁"); //将当前的线程和null进行比较,不满足则一直循环等待 while (!atomicReference.compareAndSet(null,thread)) { } System.out.println(thread.getName()+"成功获取锁"); } public void unlock() { Thread thread = Thread.currentThread(); System.out.println(thread.getName()+"解锁"); //将当前的线程和null进行比较,不满足则一直循环等待 atomicReference.compareAndSet(thread,null); } public static void main(String[] args) { MyLock myLock = new MyLock(); new Thread(()-> { try { myLock.lock(); TimeUnit.SECONDS.sleep(1); System.out.println("线程A执行操作"); } catch (Exception e) { e.printStackTrace(); }finally { myLock.unlock(); } },"A").start(); new Thread(()-> { try { TimeUnit.SECONDS.sleep(2); myLock.lock(); System.out.println("线程B执行操作"); } catch (Exception e) { e.printStackTrace(); }finally { myLock.unlock(); } },"B").start(); } }
测试结果:线程A先得到锁,线程B想要执行必须等线程A释放锁才可以执行
A尝试获取锁
A成功获取锁
线程A执行操作
A解锁
B尝试获取锁
B成功获取锁
线程B执行操作
B解锁
四,如何排查死锁