Java同步锁(synchronized)、锁(lock)以及死锁
1、实体类
1 package com.cn.donleo.thread.phone; 2 3 import java.util.concurrent.locks.Lock; 4 import java.util.concurrent.locks.ReentrantLock; 5 6 /** 7 * @author liangd 8 * date 2020-11-02 08:53 9 * code 10 */ 11 public class MyPhone implements Runnable { 12 13 private int phoneNum = 100; 14 /* 15 * 同步锁的两种方式: 16 * 1、锁对象 synchronized (this) 17 * 2、锁方法 public synchronized void run() 锁方法其实是锁的当前对象,synchronized (this) ,synchronized (MyPhone.class) 18 * 同步锁优缺点: 19 * 1、解决了多线程安全问题 20 * 2、增加了线程同步锁后,必须一个一个执行,浪费资源,降低了程序的运行效率 21 */ 22 /** 23 * 1、对不同的runnable传入同一个lock 24 * 2、lock和synchronized类似,只不过这个是手动上锁,手动释放锁 25 * synchronized属于自动上锁和释放 26 * 3、Lock和synchronized的区别 27 * 1)synchronized试用于并发量小的,lock更适用于并发量大的 28 * 2)lock更灵活,可以自由定义多把锁的枷锁解锁顺序 29 * 3)Lock还有中断锁和定时锁。 30 * 4)当线程运行到synchronized同步方法中,就会拥有obj对象的对象锁 31 * 5)Wait会释放对象锁,sleep不会释放对象锁 32 * 6)Synchronized用对象锁: 33 */ 34 private Lock lock = new ReentrantLock(); 35 36 @Override 37 public synchronized void run() { 38 //while(true)是一个无穷循环语句 我们必须在他的循环语句内部加入一个判断 当他达到了什么要求就会跳出 39 while (true) { 40 //锁对象,指当前对象 41 // synchronized (this){ 42 // synchronized ("Myphone"){ 43 if (phoneNum > 0) { 44 lock.lock(); 45 try { 46 /* 47 1、卖手机的时候不可能都是同时卖出或者被预定在MyPhone类里面增加sleep 48 休眠100毫秒 49 2、淘宝最后一部手机进来 50 京东也有人预定手机,现在没有--,也可以进来 51 同理,拼多多也有人预定手机,现在没有--,也可以进来 52 3、会出现负数 53 */ 54 Thread.sleep(100); 55 } catch (InterruptedException e) { 56 e.printStackTrace(); 57 } finally { 58 //lock.unlock()要放在finally里面,因为如果上面报异常的情况下锁就不会手动释放,放在finally里面始终要执行 59 lock.unlock(); 60 } 61 System.out.println(Thread.currentThread().getName() + "卖出了一部手机,还剩余" + --phoneNum + "部手机"); 62 } else { 63 System.out.println("手机已经全部卖完,请下次再来"); 64 return; 65 } 66 // } 67 68 } 69 } 70 }
2、测试同步锁
1 package com.cn.donleo.thread.phone; 2 3 /** 4 * @author liangd 5 * date 2020-11-02 08:59 6 * code 线程同步测试 7 */ 8 public class TestMyPhone { 9 /** 10 * 手机属于预定模式,分别由京东,淘宝,拼多多三个商家在卖 11 * 现在有华为P40PRO手机100部,怎么来实现 12 * 思考: 13 * 1.有一百部手机 14 * 2.京东,淘宝,拼多多是同时卖手机,属于三个线程 15 * 3.有一个仓库进行发货,这个可以理解为main方法 16 * @param args 17 */ 18 public static void main(String[] args){ 19 MyPhone myPhone = new MyPhone(); 20 Thread tb = new Thread(myPhone,"淘宝"); 21 Thread jd = new Thread(myPhone,"京东"); 22 Thread pdd = new Thread(myPhone,"拼多多"); 23 tb.start(); 24 jd.start(); 25 pdd.start(); 26 27 } 28 }
3、测试死锁
1 package com.cn.donleo.thread.phone; 2 3 /** 4 * @author liangd 5 * date 2020-11-02 09:42 6 * code 死锁测试 7 */ 8 public class TestSynchronized { 9 /** 10 * 1、死锁4个必要条件 11 * (1) 互斥条件:一个资源每次只能被一个进程使用。 12 * (2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 13 * (3) 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。 14 * (4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 15 * 2、如何避免死锁 16 * (1)加锁顺序(线程按照一定的顺序加锁) 17 * (2)加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁) 18 * (3)死锁检测 19 * 最简单的方式:不要写嵌套锁就好 20 */ 21 public static void main(String[] args) { 22 /* 23 * 多次测试,出现死锁,程序一直在运行,A和B都没有吃到饭 24 */ 25 //匿名内部类,直接new接口必须实现接口中的抽象方法 26 new Thread(new Runnable() { 27 @Override 28 public void run() { 29 synchronized ("A") { 30 System.out.println(Thread.currentThread().getName() + "拿到A筷子了"); 31 //嵌套锁 32 synchronized ("B") { 33 System.out.println(Thread.currentThread().getName() + "拿到A筷子了,同时拿到B筷子了,可以吃饭了"); 34 } 35 } 36 } 37 }, "男朋友").start(); 38 //再开一个线程 39 new Thread(new Runnable() { 40 @Override 41 public void run() { 42 synchronized ("B") { 43 System.out.println(Thread.currentThread().getName() + "拿到B筷子了"); 44 //嵌套锁 45 synchronized ("A") { 46 System.out.println(Thread.currentThread().getName() + "拿到B筷子了,同时拿到A筷子了,可以吃饭了"); 47 } 48 } 49 } 50 }, "女朋友").start(); 51 } 52 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix