需求:
火车站有5个窗口,有1000张火车票,同时开始售票,请用Java多线程实现
分析:
这是学习Java多线程的时候必定会遇到的一个案例
窗口一共有五个,共同操作1000张票,多以票需要定义成静态的
线程在操作的数据的时候,我们要注意数据的安全,可以使用同步代码块或同步方法,也可以通过加一锁(ReentrantLock)的方式来解决,下面我们编写代码来演示。
第一种方式:使用同步代码块+锁
package com.qf.demos;public class Demo08 {public static void main(String[] args) {// 创建Runnable,记住只需创建一次TicketRunnable tr = new TicketRunnable();// 创建线程对象Thread t1 = new Thread(tr,"1号窗口"); Thread t2 = new Thread(tr,"2号窗口"); Thread t3 = new Thread(tr,"3号窗口"); Thread t4 = new Thread(tr,"4号窗口"); Thread t5 = new Thread(tr,"5号窗口"); // 开启线程 t1.start(); t2.start(); t3.start(); t4.start(); t5.start();}}class TicketRunnable implements Runnable{ // 静态的tickets,只有一份,所有线程都操作这个数据 private static int tickets = 1000; // 静态的lock,只在内存中存在一份 private static Object lock = new Object(); @Override public void run() { while(true){ // 同步代码块,保障线程操作数据的安全 synchronized (lock) {// 这里的锁对象我们使用的是静态的lock,只在内存中存在一份 // 再次进行判断,防止出现负值 if(tickets <= 0){ break; } try{ Thread.sleep(10); } catch(InterruptedException e){ e.printStackTrace(); } // 每执行一次相当于卖掉一张票,tickets减少1 tickets--; System.out.println(Thread.currentThread().getName() + "...卖出了第" + (1000 - tickets) + "号票,还剩下" + tickets + "张票......."); } } }}
运行结果:
![00d41f3720ddb702b46ea3bcec3343fb.png](https://i-blog.csdnimg.cn/blog_migrate/105d434608777a893f8e00c7a4a07648.jpeg)
第二种方式:使用ReentrantLock(可重入锁)
ReentrantLock是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。
ReentrantLock可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。
package com.qf.demos;import java.util.concurrent.locks.ReentrantLock;public class Demo07 {public static void main(String[] args) {// 创建Runnable,记住只需创建一次TicketRunnable tr = new TicketRunnable();// 创建线程对象Thread t1 = new Thread(tr,"1号窗口"); Thread t2 = new Thread(tr,"2号窗口"); Thread t3 = new Thread(tr,"3号窗口"); Thread t4 = new Thread(tr,"4号窗口"); Thread t5 = new Thread(tr,"5号窗口"); // 开启线程 t1.start(); t2.start(); t3.start(); t4.start(); t5.start();}}class TicketRunnable implements Runnable{// 静态的tickets,只有一份,所有线程都操作这个数据 private static int tickets = 1000; // 静态的lock,只在内存中存在一份static ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {// 再次进行判断,防止出现负值while(tickets > 0) {// 每一条线程执行的时候都上锁,结束的时候解锁,保证只能有一条线程执行下面的代码lock.lock();if (tickets>0) {// 每执行一次相当于卖掉一张票,tickets减少1tickets--;System.out.println(Thread.currentThread().getName() + "正在销售第" + (1000 - tickets) + "张票");}// 解锁lock.unlock();}}}
运行结果:
![dbddc053aab8aff7cd6d8768a9e58bd9.png](https://i-blog.csdnimg.cn/blog_migrate/11f1172871e5a28ed7e7309eb3e1a41f.jpeg)