synchronized
synchronized格式
- 同步代码块的格式:
synchronized (锁对象){...}
- 非静态同步方法的格式:
public synchronized 方法返回值 方法名称 (){....}
- 静态同步方法的格式:
public static synchronized 方法返回值 方法名称(){....}
synchronized的同步代码块
1.使用同步代码块解决多线程安全问题
使用继承Thread实现多窗口卖票
| Thread实现类: |
| |
| public class MyThread extends Thread{ |
| public static int ticket = 20; |
| public static Object obj = new Object(); |
| |
| public MyThread(String name) { |
| super(name); |
| } |
| public void run(){ |
| while (true){ |
| synchronized (obj){ |
| |
| if (ticket <= 0){ |
| System.out.println("票卖完了"); |
| break; |
| }else{ |
| try { |
| Thread.sleep(100); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| System.out.println(Thread.currentThread().getName()+"在卖"+ticket+"张票"); |
| ticket--; |
| } |
| } |
| } |
| } |
| } |
| 测试类: |
| public class Test01 { |
| public static void main(String[] args) { |
| MyThread myThread1 = new MyThread("李哈哈"); |
| MyThread myThread2 = new MyThread("李嘿嘿"); |
| myThread1.start(); |
| myThread2.start(); |
| } |
| } |
2.使用同步代码块解决多个入口执行共享资源问题
多个入口操作共享资源,实现同步代码块多窗口卖票
| Thread实现类: |
| |
| public class MyThread extends Thread{ |
| public static int ticket = 60; |
| |
| public MyThread(String name) { |
| super(name); |
| } |
| public void run(){ |
| while (true){ |
| if (ticket == 0){ |
| break; |
| } |
| if (ticket % 2 == 0){ |
| synchronized (this){ |
| if (ticket > 0){ |
| System.out.println(Thread.currentThread().getName()+"在卖"+ticket+"票"); |
| ticket--; |
| } |
| } |
| }else{ |
| synchronized (this){ |
| if (ticket > 0){ |
| System.out.println(Thread.currentThread().getName()+"在卖"+ticket+"票"); |
| ticket--; |
| } |
| } |
| } |
| } |
| } |
| } |
| 测试类: |
| public class Test01 { |
| public static void main(String[] args) { |
| MyThread myThread1 = new MyThread("李哈哈"); |
| MyThread myThread2 = new MyThread("李嘿嘿"); |
| myThread1.start(); |
| myThread2.start(); |
| } |
| } |
synchronized的非静态同步方法
1.使用非静态同步方法解决多线程安全问题
使用接口Runnable和非静态同步方法多窗口卖票
| Runnable接口的实现类: |
| public class MyRunnable implements Runnable{ |
| public static int num = 20; |
| @Override |
| public void run() { |
| while (true){ |
| if (num == 0){ |
| break; |
| }else { |
| try { |
| Thread.sleep(100); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| method(); |
| } |
| } |
| |
| } |
| public synchronized void method(){ |
| if (num > 0){ |
| System.out.println(Thread.currentThread().getName()+"在卖"+num+"票"); |
| num--; |
| } |
| } |
| } |
| |
| 测试类: |
| public class Test01 { |
| public static void main(String[] args) { |
| MyRunnable myRunnable = new MyRunnable(); |
| Thread t1 = new Thread(myRunnable, "窗口1"); |
| Thread t2 = new Thread(myRunnable, "窗口2"); |
| t1.start(); |
| t2.start(); |
| } |
| } |
2.使用非静态同步方法解决多个入口执行共享资源问题
多个入口操作共享资源,实现非静态同步方法多窗口卖票
| |
| public class MyRunnable implements Runnable{ |
| public static int num = 20; |
| @Override |
| public void run() { |
| while (true){ |
| if (num == 0){ |
| break; |
| }else if (num % 2 == 0){ |
| try { |
| Thread.sleep(100); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| method1(); |
| }else { |
| method(); |
| } |
| } |
| |
| } |
| public synchronized void method(){ |
| if (num > 0){ |
| System.out.println(Thread.currentThread().getName()+"在卖"+num+"票"); |
| num--; |
| } |
| } |
| public synchronized void method1(){ |
| if (num > 0){ |
| System.out.println(Thread.currentThread().getName()+"在卖"+num+"票"); |
| num--; |
| } |
| } |
| } |
| 测试类: |
| public class Test01 { |
| public static void main(String[] args) { |
| MyRunnable myRunnable = new MyRunnable(); |
| Thread t1 = new Thread(myRunnable, "窗口1"); |
| Thread t2 = new Thread(myRunnable, "窗口2"); |
| t1.start(); |
| t2.start(); |
| } |
| } |
| |
synchronized的静态同步方法
1.使用静态同步方法解决多线程安全问题
使用静态同步方法
使用Runnable接口和静态同步方法实现多窗口卖票
| |
| public class MyRunnable implements Runnable { |
| public static int ticket = 40; |
| @Override |
| public void run() { |
| while (true){ |
| if (ticket == 0){ |
| break; |
| }else{ |
| try { |
| Thread.sleep(100); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| method(); |
| } |
| } |
| } |
| public static synchronized void method(){ |
| if (ticket > 0){ |
| System.out.println(Thread.currentThread().getName()+"卖了"+ticket+"张票"); |
| ticket--; |
| } |
| } |
| } |
| |
| 测试类: |
| public class Test01 { |
| public static void main(String[] args) { |
| MyRunnable myRunnable = new MyRunnable(); |
| Thread t1 = new Thread(myRunnable, "小姐姐"); |
| Thread t2 = new Thread(myRunnable, "大姐姐"); |
| t1.start(); |
| t2.start(); |
| } |
| } |
2.使用非静态同步方法解决多个入口执行共享资源问题
使用多个静态同步方法实现多卤肉执行共享资源
| |
| public class MyRunnable implements Runnable{ |
| public static int num = 20; |
| @Override |
| public void run() { |
| while (true){ |
| if (num == 0){ |
| break; |
| }else if (num % 2 == 0){ |
| try { |
| Thread.sleep(100); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| method1(); |
| }else { |
| method(); |
| } |
| } |
| |
| } |
| public static synchronized void method(){ |
| if (num > 0){ |
| System.out.println(Thread.currentThread().getName()+"在卖"+num+"票"); |
| num--; |
| } |
| } |
| public static synchronized void method1(){ |
| if (num > 0){ |
| System.out.println(Thread.currentThread().getName()+"在卖"+num+"票"); |
| num--; |
| } |
| } |
| } |
| 测试类: |
| public class Test01 { |
| public static void main(String[] args) { |
| MyRunnable myRunnable = new MyRunnable(); |
| Thread t1 = new Thread(myRunnable, "a"); |
| Thread t2 = new Thread(myRunnable, "b"); |
| t1.start(); |
| t2.start(); |
| } |
| } |
多入口和多窗口卖票的不同情况
多入口操作共享资源时,使用同步代码块和静态同步方法,非静态同步方法的搭配使用,实现多窗口卖票
多入口的操作共享资源的多种情况:
- 多个入口都是同步代码块时:需要保持多个同步代码块对的锁对象是同一个。
- 多个入口有同步代码块和非静态同步方法时:需要将同步代码块中的锁对象修改为this,保证同步代码块和非静态同步方法的锁对象一致
- 多个入口有同步代码块和静态同步方法时:需要将同步代码块中的锁对象修改为当前类的Class对象,有两种方式修改同步代码块中的锁改为Class对象(前类名.class或者this.getClass),这样保证了同步代码块和静态同步方法的锁对象一致。
代码实现
1.同步代码块+非静态同步方法+多入口操作共同资源
思路:
需要使得同步代码块中的锁对象和非静态同步方法中的锁对象相同,但是非静态方法中的锁默认为this,当前类,所以只有修改同步代码块中的锁对象也为this,才能保证两者锁对象相同,多个入口的锁应该使用相同的锁,所以使用同一种非静态同步方法即可。
代码块:
同步代码块+非静态同步方法
| |
| |
| |
| public class MyRunnable implements Runnable{ |
| public static int ticket = 40; |
| @Override |
| public void run() { |
| while (true){ |
| if (ticket % 3 == 0){ |
| |
| synchronized (this){ |
| if (ticket > 0){ |
| try { |
| Thread.sleep(100); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| System.out.println(Thread.currentThread().getName()+"在卖"+ticket+"号票"); |
| ticket--; |
| } |
| } |
| }else{ |
| |
| method(); |
| } |
| } |
| } |
| public synchronized void method(){ |
| if (ticket > 0){ |
| System.out.println(Thread.currentThread().getName()+"在卖"+ticket+"号票"); |
| ticket--; |
| } |
| } |
| } |
| |
2.同步代码块+静态同步方法+多入口操作共同资源
思路:
需要同步代码块中的锁对象和静态同步方法的锁对象保持一致,静态同步方法中的锁对象默认为当前类的Class对象,所以修改同步代码块中的锁对象使得两者保持一致即可。
代码块:
同步代码块+静态同步方法+多入口操作共享资源
| |
| |
| |
| public class MyRunnable implements Runnable{ |
| public static int ticket = 40; |
| @Override |
| public void run() { |
| while (true){ |
| if (ticket % 3 == 0){ |
| |
| |
| synchronized (this.getClass()){ |
| if (ticket > 0){ |
| try { |
| Thread.sleep(100); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| System.out.println(Thread.currentThread().getName()+"在卖"+ticket+"号票"); |
| ticket--; |
| } |
| } |
| }else{ |
| |
| method(); |
| } |
| } |
| } |
| public static synchronized void method(){ |
| if (ticket > 0){ |
| System.out.println(Thread.currentThread().getName()+"在卖"+ticket+"号票"); |
| ticket--; |
| } |
| } |
| } |
| |
Lock锁
使用Lock实现多线程卖票:
Lock解决多线程安全问题
| |
| public class MyRunnable implements Runnable{ |
| private static int ticket = 100; |
| Lock lock = new ReentrantLock(); |
| @Override |
| public void run() { |
| while (true){ |
| if (ticket == 0){ |
| System.out.println("票卖完了"); |
| break; |
| }else { |
| lock.lock(); |
| if (ticket > 0){ |
| try { |
| Thread.sleep(100); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| System.out.println(Thread.currentThread().getName()+"在卖"+ticket+"票"); |
| ticket--; |
| } |
| } |
| lock.unlock(); |
| } |
| } |
| } |
| |
| 测试类: |
| public class Test01 { |
| public static void main(String[] args) { |
| MyRunnable myRunnable = new MyRunnable(); |
| Thread t1 = new Thread(myRunnable,"窗口1"); |
| Thread t2 = new Thread(myRunnable,"窗口2"); |
| Thread t3 = new Thread(myRunnable,"窗口3"); |
| t1.start(); |
| t2.start(); |
| t3.start(); |
| } |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~