使用同步解决多人卖票问题 | 带你学《Java语言高级特性》之九

本文涉及的产品
文本翻译,文本翻译 100万字符
图片翻译,图片翻译 100张
语种识别,语种识别 100万字符
简介: 本节先由多人合卖10张票为例,引出了线程同步问题,并结合实例代码讲解了同步机制的实现办法。

上一篇:迅速读懂Java线程的交通规则 | 带你学《Java语言高级特性》之八
【本节目标】
通过阅读本节内容,你将了解到线程同步问题出现的原因,并学会使用synchronized关键字实现多个线程同时只有一个能进行调用的限制,解决线程同步问题。

在多线程的处理之中,可以利用Runnable描述多个线程操作的资源,而Thread描述每一个线程对象,当然多个线程访问同一资源时如果处理不当就会产生数据的错误操作。

同步问题的引出

下面编写一个简单的卖票程序,将若干个线程对象实现卖票的处理操作。
范例:实现卖票操作

class MyThread implements Runnable {
    private int ticket = 10 ;        //总票数为10张
    @Override
    public void run() {
        while (true) {
            if (this.ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket--) ;
            } else {
                System.out.println("***** 票已经卖光了 *****") ;
                break ;
            }
        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        MyThread mt=new MyThread() ;
        new Thread(mt,"票贩子A").start() ;
        new Thread(mt,"票贩子B").start() ;
        new Thread(mt,"票贩子C").start() ;
    }
}

image.png
图一 卖票程序执行

此时的程序将创建3个线程对象,并且这三个线程将进行10张票的出售。此时的程序在进行卖票处理的时候,并没有任何的问题(假象),下面可以模拟一下卖票中的延迟操作。

class MyThread implements Runnable {
    private int ticket = 10;       //总票数为10张
    @Override
    public void run() {
        while (true) {
            if (this.ticket > 0) {
                try {
                    Thread.sleep(100);    //模拟网络延迟
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket--);
            } else {
                System.out.println("***** 票已经卖光了 *****");
                break;
            }
        }
    }
}

image.png
图二 卖票问题执行操作

这个时候追加了延迟,问题就暴露出来了,而实际上这个问题一直都在。

image.png
图三 卖票处理

线程同步处理

经过分析之后已经可以确定同步问题产生的主要原因了,那么下面就需要进行同步问题的解决,但是解决同步问题的关键是锁,指的是当某一个线程执行操作的时候,其他线程外面等待;

image.png
图四 问题的解决

如果要想程序中实现这把锁功能,就可以使用synchronized关键字来实现,利用此关键字可以定义同步方法或同步代码块,在同步代码块的操作中的代码只允许一个线程执行。
1、利用同步代码块进行处理:

synchronized (同步对象){
    同步代码操作;
}

一般要进行同步对象处理的时候可以采用当前对象this进行同步。
范例:利用同步代码块解决数据同步访问问题

class MyThread implements Runnable {
    private int ticket = 10 ;    //总票数为10张
    @Override
    public void run() {
        while (true) {
            synchronized (this) {    //每一次只允许一个线程进行访问
                if (this.ticket > 0) {
                    try {
                        Thread.sleep(100);     //模拟网络延迟
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket--);
                } else {
                    System.out.println("***** 票已经卖光了 *****");
                    break;
                }
            }
        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        new Thread(mt, "票贩子A").start();
        new Thread(mt, "票贩子B").start();
        new Thread(mt, "票贩子C").start();
    }
}

加入同步处理之后,程序的整体性能下降了。同步实际上会造成性能的降低。

2、利用同步方法解决:只需要在方法定义上使用synchronized关键字即可。

class MyThread implements Runnable {
    private int ticket = 10;    //总票数为10张
    public synchronized boolean sale() {
        if (this.ticket > 0) {
            try {
                Thread.sleep(100);    //模拟网络延迟
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖票,ticket = " + this.ticket--);
            return true;
        } else {
            System.out.println("***** 票已经卖光了 *****");
            return false;
        }
    }
    @Override
    public void run() {
        while ( this.sale()) {}
    }
}
public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        new Thread(mt, "票贩子A").start();
        new Thread(mt, "票贩子B").start();
        new Thread(mt, "票贩子C").start();
    }
}

image.png
图五 解决同步问题

在日后学习Java类库的时候,系统中许多的类上使用的同步处理采用的都是同步方法。

想学习更多的Java的课程吗?从小白到大神,从入门到精通,更多精彩不容错过!免费为您提供更多的学习资源。
本内容视频来源于阿里云大学

下一篇:同步的缺陷-死锁问题 | 带你学《Java语言高级特性》之十
更多Java面向对象编程文章查看此处

相关文章
|
1月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
69 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
25天前
|
存储 安全 Java
Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
【10月更文挑战第17天】Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
52 2
|
9天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
22 4
|
1月前
|
存储 消息中间件 安全
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
【10月更文挑战第9天】本文介绍了如何利用JUC组件实现Java服务与硬件通过MQTT的同步通信(RRPC)。通过模拟MQTT通信流程,使用`LinkedBlockingQueue`作为消息队列,详细讲解了消息发送、接收及响应的同步处理机制,包括任务超时处理和内存泄漏的预防措施。文中还提供了具体的类设计和方法实现,帮助理解同步通信的内部工作原理。
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
|
17天前
|
Java 调度
Java 线程同步的四种方式,最全详解,建议收藏!
本文详细解析了Java线程同步的四种方式:synchronized关键字、ReentrantLock、原子变量和ThreadLocal,通过实例代码和对比分析,帮助你深入理解线程同步机制。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Java 线程同步的四种方式,最全详解,建议收藏!
|
23天前
|
存储 Java API
优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。
【10月更文挑战第19天】本文介绍了如何优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。内容包括Map的初始化、使用Stream API处理Map、利用merge方法、使用ComputeIfAbsent和ComputeIfPresent,以及Map的默认方法。这些技巧不仅提高了代码的可读性和维护性,还提升了开发效率。
45 3
|
23天前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
33 1
|
23天前
|
存储 安全 Java
Java Map新玩法:深入探讨HashMap和TreeMap的高级特性
【10月更文挑战第19天】Java Map新玩法:深入探讨HashMap和TreeMap的高级特性,包括初始容量与加载因子的优化、高效的遍历方法、线程安全性处理以及TreeMap的自然排序、自定义排序、范围查询等功能,助你提升代码性能与灵活性。
24 2
|
30天前
|
Java 程序员 编译器
在Java编程中,保留字(如class、int、for等)是具有特定语法意义的预定义词汇,被语言本身占用,不能用作变量名、方法名或类名。
在Java编程中,保留字(如class、int、for等)是具有特定语法意义的预定义词汇,被语言本身占用,不能用作变量名、方法名或类名。本文通过示例详细解析了保留字的定义、作用及与自定义标识符的区别,帮助开发者避免因误用保留字而导致的编译错误,确保代码的正确性和可读性。
42 3
|
1月前
|
移动开发 Java 大数据
深入探索Java语言的核心优势与现代应用实践
【10月更文挑战第10天】深入探索Java语言的核心优势与现代应用实践
50 4