Java JUC并发之对于各种锁的理解以及如何解决死锁问题
2021/7/19 9:06:59
本文主要是介绍Java JUC并发之对于各种锁的理解以及如何解决死锁问题,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
对于各种锁的理解
-
公平锁、非公平锁
公平锁 : 不允许插队,必须先来后到
非公平锁: 允许插队(默认都是非公平锁)
-
可重入锁
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(); } } }
可重入锁(递归锁)=> 可以递归调用和嵌套
- 拿到外面的多之后,就可以自动获得里面的锁
- lock锁必须配对,否则会导致死锁
-
自旋锁 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终端上可以使用这些命令排查问题
- 使用 jps -l查询运行的进程号
- 使用 jstack 进程号 => 查看死锁信息
面试: 工作中如何排查问题(死锁)
- 日志
- 堆栈 jstack
这篇关于Java JUC并发之对于各种锁的理解以及如何解决死锁问题的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-16MyBatis-Plus资料入门教程:快速上手指南
- 2024-11-16Mybatis资料入门教程:新手必看指南
- 2024-11-16MyBatis资料详解:新手入门与初级实战指南
- 2024-11-16MyBatisPlus资料:初学者入门指南与实用教程
- 2024-11-16MybatisPlus资料详解:初学者入门指南
- 2024-11-16MyBatisX资料:新手入门与初级教程
- 2024-11-16RESTful接口资料详解:新手入门指南
- 2024-11-16RESTful接口资料详解:新手入门教程
- 2024-11-16Spring Boot资料:新手入门与初级教程
- 2024-11-16Springboot资料:新手入门与初级教程