线程安全处理的3种方式
一、模拟电影院的卖票过程。假设要播放的电影是 “唐人街探案3”,本次电影的座位共100个(本场电影只能卖100张票)。
代码如下:
public class Tickects implements Runnable { private int ticket=100; public void run() { //int ticket=100 自己独有数据 不是共享数据 所以int ticket=100不能写到这个地方 while(true){ if(ticket>0){ try { Thread.sleep(500); //这个地方加sleep睡眠状态 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"售出了第"+ticket--+"张票"); } } } }
public class Demo01 { public static void main(String[] args) { //创建线程任务 Tickects t=new Tickects(); //创建线程对象 Thread t1=new Thread(t); Thread t2=new Thread(t); Thread t3=new Thread(t); t1.start(); t2.start(); t3.start(); }
运行结果如下:
出现的问题:出现重复票 错误票0
解决方法:①同步代码块 使用 synchronized 关键字 (锁对象){可能出现问题的代码}
public class Tickects02 implements Runnable { private int ticket=10; private Object obj=new Object(); public void run() { while(true){ synchronized (obj) { //还可以直接用this 结果是一样的 //可能发生问题的代码块问题代码 if(ticket>0){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"售出了第"+ticket--+"张票"); } } } } } public class Demo02 { public static void main(String[] args) { //创建线程任务 Tickects02 t=new Tickects02(); //创建线程对象 Thread t1=new Thread(t); Thread t2=new Thread(t); Thread t3=new Thread(t); t1.start(); t2.start(); t3.start(); } }
② 同步方法
public synchronized void method(){
可能会产生线程安全问题的代码
}
public class Tickects03 implements Runnable { private int ticket=100; public void run() { while(true){ sale(); //调用下面这个sale()对象 } } //同步方法(内置锁对象this) public synchronized void sale(){ if(ticket>0){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"售出了第"+ticket--+"张票"); } } } public class Demo03 { public static void main(String[] args) { //创建线程任务 Tickects03 t=new Tickects03(); //创建线程对象 Thread t1=new Thread(t); Thread t2=new Thread(t); Thread t3=new Thread(t); t1.start(); t2.start(); t3.start(); } }
③用Lock 接口
public class Tickects04 implements Runnable { private int ticket=100; //lock 接口实现类对象 private Lock lock=new ReentrantLock(); public void run() { while(true){ lock.lock(); if(ticket>0){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"售出了第"+ticket--+"张票"); } //释放锁 lock.unlock(); } } } public class Demo04 { public static void main(String[] args) { //StringBuffer和StringBuilder //StringBuffer 速度慢安全 (慢:线程同步) //StringBuilder 速度快 不安全 比较适合单线程 //创建线程任务 Tickects04 t=new Tickects04(); //创建线程对象 Thread t1=new Thread(t); Thread t2=new Thread(t); Thread t3=new Thread(t); t1.start(); t2.start(); t3.start(); } }
这三种方法打印出结果是相同的:
无重复,无错误票;
欢迎各位大神指点和评论,多多交流;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程