解决线程安全问题
方式一:同步代码块
synchronized (同步监视器){
//需要被同步的代码
}
说明:
操作共享数据的代码,即为需要被同步的代码
共享数据:多个线程共同操作的变量
同步监视器:俗称,锁。任何一个类的对象都可以充当锁。(要求:多个线程必须要共用同一把锁)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | public class Window implements Runnable { private int ticket = 100 ; private Object obj = new Object(); @Override public void run() { while ( true ) { synchronized (obj) { //可以用this,此时的this:唯一的Window的对象 if (ticket > 0 ) { try { Thread.sleep( 100 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "***" + ticket); ticket--; } else { break ; } } } } } class WindowTest { public static void main(String[] args) { Window w = new Window(); Thread t1 = new Thread(w); //3个线程公用1个w对象 Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName( "线程1" ); t2.setName( "线程2" ); t3.setName( "线程3" ); t1.start(); t2.start(); t3.start(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | public class ThreadTest { public static void main(String[] args) { Window1 t1 = new Window1(); Window1 t2 = new Window1(); Window1 t3 = new Window1(); t1.setName( "线程1" ); t2.setName( "线程2" ); t3.setName( "线程3" ); t1.start(); t2.start(); t3.start(); } } class Window1 extends Thread{ private static int ticket = 100 ; private static Object obj = new Object(); @Override public void run() { while ( true ) { synchronized (obj) { //可以用Window1.class,类也是对象,在内存中只加载一次 if (ticket > 0 ) { try { Thread.sleep( 100 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "***" + ticket); ticket--; } else { break ; } } } } } |
方式二:同步方法
如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明为同步的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | public class Window implements Runnable { private int ticket = 100 ; @Override public void run() { while ( true ) { sale(); if (ticket== 0 ){ return ; } } } //方法中加synchronized关键字,同步监视器:this public synchronized void sale(){ if (ticket > 0 ) { try { Thread.sleep( 100 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "***" + ticket); ticket--; } } } class WindowTest { public static void main(String[] args) { Window w = new Window(); Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName( "线程1" ); t2.setName( "线程2" ); t3.setName( "线程3" ); t1.start(); t2.start(); t3.start(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | public class ThreadTest { public static void main(String[] args) { Window1 t1 = new Window1(); Window1 t2 = new Window1(); Window1 t3 = new Window1(); t1.setName( "线程1" ); t2.setName( "线程2" ); t3.setName( "线程3" ); t1.start(); t2.start(); t3.start(); } } class Window1 extends Thread { private static int ticket = 100 ; @Override public void run() { while ( true ) { sale(); if (ticket == 0 ) { return ; } } } <br> //同步监视器:当前类本身Window1.class public static synchronized void sale() { if (ticket > 0 ) { try { Thread.sleep( 100 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "***" + ticket); ticket--; } } } |
方式三:lock锁----jdk5.0新增
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | public class LockTest { public static void main(String[] args) { Window2 w2 = new Window2(); Thread t1 = new Thread(w2); Thread t2 = new Thread(w2); Thread t3 = new Thread(w2); t1.setName( "窗口1" ); t2.setName( "窗口2" ); t3.setName( "窗口3" ); t1.start(); t2.start(); t3.start(); } } class Window2 implements Runnable { private int ticket = 100 ; //1.实例化ReentrantLock private ReentrantLock lock = new ReentrantLock(); @Override public void run() { while ( true ) { try { //2.调用锁定方法lock() lock.lock(); if (ticket > 0 ){ try { Thread.sleep( 100 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+ "正在售票" +ticket); ticket--; } else { break ; } } finally { //3.调用解锁方法unlock() lock.unlock(); } } } } |
synchronized和lock异同
相同:都可以解决线程安全问题
不同:synchronized机制在执行完相应的同步代码以后,自动释放锁。
lock需要手动的启动同步,同时结束同步也需要手动的释放

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!