各种锁的理解公平锁、非公平锁
公平锁:先到先得(不可插队)
非公平锁:达者为先(可插队)———->默认
public ReentrantLock() { //默认非公平锁 sync = new NonfairSync();}
//重载的构造方法,通过fair控制是否公平public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync();}
可重入锁(递归锁)
所有的锁都是可重入锁
Synchronized版
package org.example.lock;public class Demo01 { public static void main(String[] args) { phone1 p1 = new phone1(); new Thread(()->{ p1.ems(); },"A").start(); new Thread(()->{ p1.ems(); },"B").start(); }}class phone1{ public synchronized void ems(){ System.out.println(Thread.currentThread().getName()+"---------->ems"); call(); } public synchronized void call(){ System.out.println(Thread.currentThread().getName()+"---------->call"); }}
ems方法中包含了call方法,所以当我们调用ems方法获取到锁时,也把call方法的synchronized锁获取到了。
错误理论
- 当线程A运行ems方法后运行call方法时ems锁释放,线程B可以获取到ems方法
正确理论
- 当线程A运行ems方法后运行call方法时ems方法的锁还未释放时就拿到了call方法中的锁,当call方法的锁释放后ems方法的锁才会释放。线程B此时就可以运行ems方法了
Lock版
package org.example.lock;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Demo02 { public static void main(String[] args) { phone2 p2 = new phone2(); new Thread(()->{ p2.ems(); },"A").start(); new Thread(()->{ p2.ems(); },"B").start(); }}class phone2{ Lock lock = new ReentrantLock(); public void ems(){ lock.lock(); try { System.out.println(Thread.currentThread().getName()+"---------->ems"); call(); } catch (Exception e) { e.printStackTrace(); } finally { //等待call方法锁解锁后再解锁 lock.unlock(); } } public void call(){ lock.lock(); try { System.out.println(Thread.currentThread().getName()+"---------->call"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } }}
自旋锁
spinlock(不断尝试直至成功)
已经见过了,就是unsafe中的自增getAndAddInt方法中的do-while循环就是一把自旋锁
自己写一把锁
package org.example.lock;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicReference;public class SpinLockDemo { //int 0 //Thread null public static AtomicReference atomic = new AtomicReference(); public static void lock(){ Thread thread = Thread.currentThread(); System.out.println("===============>"+thread.getName()+"===========>lock"); //自旋锁,若线程等于null,则compareAndSet为true,加!就为false,就会一直循环 while (!atomic.compareAndSet(null,thread)){ } } public static void unlock(){ Thread thread = Thread.currentThread(); System.out.println("===============>"+thread.getName()+"===========>unlock"); //自旋锁 atomic.compareAndSet(thread,null); } public static void main(String[] args) throws InterruptedException { new Thread(()->{ try { lock(); TimeUnit.SECONDS.sleep(10); } catch (Exception e) { e.printStackTrace(); } finally { unlock(); } },"A").start(); TimeUnit.SECONDS.sleep(1); new Thread(()->{ try { lock(); TimeUnit.SECONDS.sleep(2); } catch (Exception e) { e.printStackTrace(); } finally { unlock(); } },"B").start(); }}
死锁
死锁是什么
死锁测试
package org.example.lock;import java.util.concurrent.TimeUnit;public class DeadLockDemo { public static void main(String[] args) { String a = "A"; String b = "B"; new Thread(()->{new MyThread(a, b).run();},"A").start(); new Thread(()->{new MyThread(b, a).run();},"B").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+"=>get"+lockB); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { throw new RuntimeException(e); } synchronized (lockB){ System.out.println(Thread.currentThread().getName()+"lock:"+lockB+"=>get"+lockA); } } }}
程序突然卡住死锁如何排查?
1、使用jps-l
定位进程号
查看当前java活着的进程
2、使用jstack 进程号
查看死锁问题
查找到一个死锁问题!
面试或者工作中排查问题:
1、查看异常
2、查看日志
3、查看堆栈信息