前言:
本文内容:可重入锁、自旋锁、死锁排查
推荐免费JUC并发编程视频:【狂神说Java】JUC并发编程最新版通俗易懂_哔哩哔哩_bilibili
JUC笔记代码下载地址:
蓝奏云:下载地址 密码:joker
百度云:下载地址 提取码:3siw
可重入锁
公平锁和非公平锁
默认锁都是非公平锁
1 2 3 4 5 6 7 8 public ReentrantLock () { sync = new NonfairSync (); } public ReentrantLock (boolean fair) { sync = fair ? new FairSync () : new NonfairSync (); }
可重入锁
可重入锁(递归锁)
同一线程外层函数获得锁之后,内层递归函数仍然有获取该锁的代码,但不受影响。
synchronized
可重入锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package com.jokerdig.lock;public class Demo01 { public static void main (String[] args) { Phone phone = new Phone (); new Thread (()->{ phone.sms(); },"A" ).start(); new Thread (()->{ phone.sms(); },"B" ).start(); } } class Phone { public synchronized void sms () { System.out.println(Thread.currentThread().getName()+"sms" ); call(); } public synchronized void call () { System.out.println(Thread.currentThread().getName()+"call" ); } }
运行结果
1 2 3 4 5 6 Asms Acall Bsms Bcall Process finished with exit code 0
lock
可重入锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package com.jokerdig.lock;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class Demo02 { public static void main (String[] args) { Phone1 phone = new Phone1 (); new Thread (()->{ phone.sms(); },"A" ).start(); new Thread (()->{ phone.sms(); },"B" ).start(); } } class Phone1 { Lock lock = new ReentrantLock (); public void sms () { lock.lock(); try { System.out.println(Thread.currentThread().getName()+"sms" ); call(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void call () { lock.lock(); try { System.out.println(Thread.currentThread().getName()+"call" ); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
运行结果
1 2 3 4 5 6 Asms Acall Bsms Bcall Process finished with exit code 0
自旋锁
当一个线程尝试去获取某一把锁的时候,如果这个锁此时已经被别人获取(占用),那么此线程就无法获取到这把锁,该线程将会等待,间隔一段时间后会再次尝试获取。这种采用循环加锁 -> 等待的机制被称为自旋锁(spinlock)
简单测试
SpinLockDemo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package com.jokerdig.lock;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)){ } } public void myUnLock () { Thread thread = Thread.currentThread(); System.out.println(Thread.currentThread().getName()+"==> myUnLock" ); atomicReference.compareAndSet(thread,null ); } }
Test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package com.jokerdig.lock;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.ReentrantLock;public class Test { public static void main (String[] args) throws InterruptedException { SpinLockDemo spinLockDemo = new SpinLockDemo (); new Thread (()->{ spinLockDemo.myLock(); try { TimeUnit.SECONDS.sleep(3 ); } catch (Exception e) { e.printStackTrace(); } finally { spinLockDemo.myUnLock(); } },"A" ).start(); TimeUnit.SECONDS.sleep(1 ); new Thread (()->{ spinLockDemo.myLock(); try { TimeUnit.SECONDS.sleep(1 ); } catch (Exception e) { e.printStackTrace(); } finally { spinLockDemo.myUnLock(); } },"B" ).start(); } }
运行结果
1 2 3 4 5 6 A==> myLock B==> myLock A==> myUnLock B==> myUnLock Process finished with exit code 0
死锁排查
死锁概念
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。
死锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 package com.jokerdig.lock;import lombok.SneakyThrows;import java.util.concurrent.TimeUnit;public class DeadLock { 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()+"lock:" +lockA+"get==>" +lockB); try { TimeUnit.SECONDS.sleep(2 ); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lockB){ System.out.println(Thread.currentThread()+"lock:" +lockB+"get==>" +lockA); } } } }
运行结果
程序一直在运行
1 2 Thread[T1,5 ,main]lock:lockAget==>lockB Thread[T2,5 ,main]lock:lockBget==>lockA
死锁排查
使用jps -l
定位进程号
1 2 3 4 5 6 7 D:\Project\project3\JUC>jps -l 12272 sun.tools.jps.Jps 4244 com.jokerdig.lock.DeadLock 7896 org.jetbrains.jps.cmdline.Launcher 8792 org.jetbrains.idea.maven.server.RemoteMavenServer36 12652
使用jstack 进程号
查看进程信息
jstack 4244
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 Found one Java-level deadlock: ============================= "T2" : waiting to lock monitor 0x0000000002e9c098 (object 0x00000000d 5effc70, a java.lang.String), which is held by "T1" "T1" : waiting to lock monitor 0x0000000002e9ea88 (object 0x00000000d 5effca8, a java.lang.String), which is held by "T2" Java stack information for the threads listed above: =================================================== "T2" : at com.jokerdig.lock.myThread.run(DeadLock.java:42 ) - waiting to lock <0x00000000d5effc70 > (a java.lang.Stri ng) - locked <0x00000000d5effca8 > (a java.lang.String) at java.lang.Thread.run(Thread.java:748 ) "T1" : at com.jokerdig.lock.myThread.run(DeadLock.java:42 ) - waiting to lock <0x00000000d5effca8 > (a java.lang.Stri ng) - locked <0x00000000d5effc70 > (a java.lang.String) at java.lang.Thread.run(Thread.java:748 ) Found 1 deadlock.