JUC并发编程(终章)各种锁的理解
1.JUC并发编程学习笔记(二)Lock锁(重点)2.JUC并发编程学习笔记(一)认知进程和线程3.JUC并发编程学习笔记(三)生产者和消费者问题4.JUC并发编程学习笔记(四)8锁现象5.JUC并发编程学习(五)集合类不安全6.JUC并发编程学习笔记(六)Callable(简单)7.JUC并发编程学习笔记(七)常用的辅助类8.JUC并发编程学习笔记(八)读写锁9.JUC并发编程学习笔记(九)阻塞队列10.JUC并发编程学习笔记(十)线程池(重点)11.JUC并发编程学习(十一)四大函数式接口(必备)12.JUC并发编程学习笔记(十二)Stream流式计算13.JUC并发编程学习(十三)ForkJoin14.JUC并发编程学习笔记(十四)异步回调15.JUC并发编程学习笔记(十五)JMM16.JUC并发编程学习笔记(十七)彻底玩转单例模式17.JUC并发编程学习笔记(十九)原子引用
18.JUC并发编程(终章)各种锁的理解
19.JUC并发编程学习笔记(十六)Volatile20.JUC并发编程学习笔记(十八)深入理解CAS各种锁的理解
公平锁、非公平锁
公平锁:先到先得(不可插队)
非公平锁:达者为先(可插队)---------->默认
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<Thread> 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、查看堆栈信息
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
2022-11-16 Spring注解开发