线程的同步
一.线程的安全问题:
1.问题:卖票过程中出现重票和错票问题(线程不安全问题)
2.出现原因:当某个线程的操作尚未完成时,其他线程的操作就参与进来。(即多个线程同时共用一块数据)
3.解决措施:当一个线程在操作共享数据时,其他线程不能参与进来(直到原线程操作完其他线程才可以参与进来)
该情况即使在原线程发生了阻塞也不会改变这种情况
4.在Java中通过同步机制来解决线程安全问题
二.同步代码块方法:
说明:1.操作共享数据的代码,即为需要被同步的代码(所包的代码不能多也不能少)
2.共享数据:多个线程中共同操作的变量(本例即为ticket)
3.同步监视器(锁):任何一个类的对象都可以作为锁
要求:多个线程必须共同使用同一把锁(否则无法保证线程安全)
补充:可以考虑适用this.class来做锁
好处:较为简易的解决了线程安全问题。
坏处:将多线程转为单线程来解决问题,效率较低
1.同步代码块解决继承Thread类的线程安全问题
代码及解析:
1 class Window extends Thread { 2 private static int ticket = 100;//所有同类对象共享static变量 3 4 private static Object obj = new Object();//保证用同一把锁 5 6 public void run() { 7 while (true) { 8 synchronized (obj) { 9 if (ticket > 0) { 10 try { 11 Thread.sleep(1000); 12 } catch (InterruptedException e) { 13 throw new RuntimeException(e); 14 } 15 System.out.println(getName() + "卖票,票号为:" + ticket); 16 ticket--; 17 } else { 18 break; 19 } 20 } 21 } 22 } 23 }
2.解决Runnable接口的实现方式的线程安全问题:
1 class Window2 implements Runnable { 2 private int ticket = 100; 3 Object obj = new Object(); 4 @Override 5 public void run() { 6 while (true) { 7 //方式一:同步代码块 8 synchronized (obj) { 9 if (ticket > 0) { 10 System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket); 11 ticket--; 12 } else { 13 break; 14 } 15 } 16 } 17 } 18 }
三.同步方法
1.同步方法仍然设计到同步监视器(锁),但不需要我们显示声明
2.静态方法的锁为this.class,非静态方法的锁为this
1.使用同步方法解决Thread类的继承问题
1 class Window4 extends Thread { 2 private static int ticket = 100;//所有同类对象共享static变量 3 4 private static Object obj = new Object();//保证用同一把锁 5 6 public void run() { 7 while (true) { 8 9 } 10 } 11 12 private static synchronized void show() {//使用静态同步方法实现(静态保证锁相同(静态使锁设为当前对象的类)) 13 if (ticket > 0) { 14 try { 15 Thread.sleep(100); 16 } catch (InterruptedException e) { 17 throw new RuntimeException(e); 18 } 19 System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket); 20 ticket--; 21 } 22 } 23 }
2.解决Runnable接口的线程安全问题:
1 class Window3 implements Runnable { 2 private int ticket = 100; 3 Object obj = new Object(); 4 @Override 5 public void run() { 6 while (ticket > 0) { 7 show(); 8 } 9 } 10 11 public synchronized void show() {//使用同步方法 12 if (ticket > 0) { 13 try { 14 Thread.sleep(1000); 15 } catch (InterruptedException e) { 16 throw new RuntimeException(e); 17 } 18 System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket); 19 ticket--; 20 } 21 } 22 }
四.锁的添加
1 class Window implements Runnable { 2 private int ticket = 100; 3 //1.实例化ReentrantLock 4 private ReentrantLock lock = new ReentrantLock(true); 5 6 public void run() { 7 try { 8 //2.调用锁定方法lock() 9 lock.lock(); 10 while (true) { 11 if (ticket > 0) { 12 System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket); 13 ticket--; 14 } else { 15 break; 16 } 17 } 18 } finally { 19 //3.调用解锁方法unlock() 20 lock.unlock(); 21 } 22 23 } 24 }
synchronized与Lock的不同点
synchronized机制:在执行完对应的代码块后,自动的释放同步监视器
Lock机制:需要手动的启动同步(Lock()),结束同步也需要手动的实现(Unlock())
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!