1.基于继承Thread实现
代码实现:
/** * 多线程模拟售票,基于Thread */ public class TicketSalesByThread { public static void main(String[] args) { SellTicket sellTicket = new SellTicket(); SellTicket sellTicket1 = new SellTicket(); SellTicket sellTicket2 = new SellTicket(); sellTicket.start(); sellTicket1.start(); sellTicket2.start(); } } class SellTicket extends Thread { // 余票 private static int ticketNum = 100; @Override public void run() { while (true) { if (ticketNum <= 0) { System.out.println("没有余票!"); break; } // 休眠卖票 try { Thread.sleep(50); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("窗口" + Thread.currentThread().getName() + "售出一张票。" + "剩余票数:" + (--ticketNum)); } } }
结果分析:
窗口Thread-1售出一张票。剩余票数:97 窗口Thread-0售出一张票。剩余票数:98 窗口Thread-2售出一张票。剩余票数:99 窗口Thread-0售出一张票。剩余票数:96 窗口Thread-1售出一张票。剩余票数:96 窗口Thread-2售出一张票。剩余票数:95 窗口Thread-0售出一张票。剩余票数:94 窗口Thread-1售出一张票。剩余票数:93 窗口Thread-2售出一张票。剩余票数:92 窗口Thread-0售出一张票。剩余票数:91 窗口Thread-1售出一张票。剩余票数:90 窗口Thread-2售出一张票。剩余票数:89 窗口Thread-0售出一张票。剩余票数:88 窗口Thread-1售出一张票。剩余票数:87 窗口Thread-2售出一张票。剩余票数:86 窗口Thread-0售出一张票。剩余票数:85 窗口Thread-1售出一张票。剩余票数:84 窗口Thread-2售出一张票。剩余票数:83 窗口Thread-0售出一张票。剩余票数:82 窗口Thread-1售出一张票。剩余票数:81 窗口Thread-2售出一张票。剩余票数:80 窗口Thread-0售出一张票。剩余票数:79 窗口Thread-1售出一张票。剩余票数:78 窗口Thread-2售出一张票。剩余票数:77 窗口Thread-0售出一张票。剩余票数:76 窗口Thread-1售出一张票。剩余票数:75 窗口Thread-2售出一张票。剩余票数:74 窗口Thread-0售出一张票。剩余票数:73 窗口Thread-1售出一张票。剩余票数:72 窗口Thread-2售出一张票。剩余票数:71 窗口Thread-0售出一张票。剩余票数:70 窗口Thread-1售出一张票。剩余票数:69 窗口Thread-2售出一张票。剩余票数:68 窗口Thread-0售出一张票。剩余票数:67 窗口Thread-1售出一张票。剩余票数:66 窗口Thread-2售出一张票。剩余票数:65 窗口Thread-0售出一张票。剩余票数:64 窗口Thread-1售出一张票。剩余票数:63 窗口Thread-2售出一张票。剩余票数:62 窗口Thread-0售出一张票。剩余票数:61 窗口Thread-1售出一张票。剩余票数:60 窗口Thread-2售出一张票。剩余票数:59 窗口Thread-0售出一张票。剩余票数:58 窗口Thread-1售出一张票。剩余票数:57 窗口Thread-2售出一张票。剩余票数:56 窗口Thread-0售出一张票。剩余票数:55 窗口Thread-1售出一张票。剩余票数:54 窗口Thread-2售出一张票。剩余票数:53 窗口Thread-0售出一张票。剩余票数:52 窗口Thread-1售出一张票。剩余票数:51 窗口Thread-2售出一张票。剩余票数:50 窗口Thread-0售出一张票。剩余票数:49 窗口Thread-1售出一张票。剩余票数:48 窗口Thread-2售出一张票。剩余票数:47 窗口Thread-0售出一张票。剩余票数:46 窗口Thread-1售出一张票。剩余票数:45 窗口Thread-2售出一张票。剩余票数:44 窗口Thread-0售出一张票。剩余票数:43 窗口Thread-1售出一张票。剩余票数:42 窗口Thread-2售出一张票。剩余票数:41 窗口Thread-0售出一张票。剩余票数:40 窗口Thread-1售出一张票。剩余票数:39 窗口Thread-2售出一张票。剩余票数:38 窗口Thread-0售出一张票。剩余票数:37 窗口Thread-1售出一张票。剩余票数:36 窗口Thread-2售出一张票。剩余票数:35 窗口Thread-0售出一张票。剩余票数:34 窗口Thread-1售出一张票。剩余票数:33 窗口Thread-2售出一张票。剩余票数:32 窗口Thread-0售出一张票。剩余票数:31 窗口Thread-1售出一张票。剩余票数:30 窗口Thread-2售出一张票。剩余票数:29 窗口Thread-0售出一张票。剩余票数:28 窗口Thread-1售出一张票。剩余票数:27 窗口Thread-2售出一张票。剩余票数:26 窗口Thread-0售出一张票。剩余票数:25 窗口Thread-1售出一张票。剩余票数:24 窗口Thread-2售出一张票。剩余票数:23 窗口Thread-0售出一张票。剩余票数:22 窗口Thread-1售出一张票。剩余票数:21 窗口Thread-2售出一张票。剩余票数:20 窗口Thread-0售出一张票。剩余票数:19 窗口Thread-1售出一张票。剩余票数:18 窗口Thread-2售出一张票。剩余票数:17 窗口Thread-0售出一张票。剩余票数:16 窗口Thread-1售出一张票。剩余票数:15 窗口Thread-2售出一张票。剩余票数:14 窗口Thread-0售出一张票。剩余票数:13 窗口Thread-1售出一张票。剩余票数:12 窗口Thread-2售出一张票。剩余票数:11 窗口Thread-0售出一张票。剩余票数:10 窗口Thread-1售出一张票。剩余票数:9 窗口Thread-2售出一张票。剩余票数:8 窗口Thread-0售出一张票。剩余票数:7 窗口Thread-1售出一张票。剩余票数:6 窗口Thread-2售出一张票。剩余票数:5 窗口Thread-0售出一张票。剩余票数:4 窗口Thread-1售出一张票。剩余票数:3 窗口Thread-2售出一张票。剩余票数:2 窗口Thread-0售出一张票。剩余票数:1 窗口Thread-1售出一张票。剩余票数:0 没有余票! 窗口Thread-2售出一张票。剩余票数:-1 没有余票! 窗口Thread-0售出一张票。剩余票数:-2 没有余票!
可以看到,基于Thread
的实现,出现了明显的超卖现象!😶🌫️
那么,为什么会发生这种情况呢?
原因分析:
当一个窗口还未执行--ticketNum
操作时,另一个窗口已经进行售票状态,跳过了while
循环的限制
2.基于实现Runnable接口实现
代码实现:
/** * 多线程模拟售票,基于实现Runnable接口 */ public class TicketSalesByRunnable { public static void main(String[] args) { SellTicket02 sellTicket02 = new SellTicket02(); new Thread(sellTicket02).start(); new Thread(sellTicket02).start(); new Thread(sellTicket02).start(); } } class SellTicket02 implements Runnable { private int ticketNum = 100; @Override public void run() { while (true) { if (ticketNum <= 0) { System.out.println("没有余票!"); break; } // 休眠卖票 try { Thread.sleep(50); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("窗口" + Thread.currentThread().getName() + "售出一张票。" + "剩余票数:" + (--ticketNum)); } } }
结果分析:
窗口Thread-0售出一张票。剩余票数:99 窗口Thread-2售出一张票。剩余票数:98 窗口Thread-1售出一张票。剩余票数:98 窗口Thread-0售出一张票。剩余票数:97 窗口Thread-2售出一张票。剩余票数:96 窗口Thread-1售出一张票。剩余票数:95 窗口Thread-0售出一张票。剩余票数:94 窗口Thread-2售出一张票。剩余票数:94 窗口Thread-1售出一张票。剩余票数:93 窗口Thread-2售出一张票。剩余票数:92 窗口Thread-0售出一张票。剩余票数:91 窗口Thread-1售出一张票。剩余票数:90 窗口Thread-2售出一张票。剩余票数:89 窗口Thread-0售出一张票。剩余票数:88 窗口Thread-1售出一张票。剩余票数:87 窗口Thread-0售出一张票。剩余票数:86 窗口Thread-2售出一张票。剩余票数:85 窗口Thread-1售出一张票。剩余票数:84 窗口Thread-2售出一张票。剩余票数:83 窗口Thread-0售出一张票。剩余票数:83 窗口Thread-1售出一张票。剩余票数:82 窗口Thread-2售出一张票。剩余票数:80 窗口Thread-0售出一张票。剩余票数:81 窗口Thread-1售出一张票。剩余票数:79 窗口Thread-2售出一张票。剩余票数:77 窗口Thread-0售出一张票。剩余票数:78 窗口Thread-1售出一张票。剩余票数:76 窗口Thread-2售出一张票。剩余票数:75 窗口Thread-0售出一张票。剩余票数:74 窗口Thread-1售出一张票。剩余票数:73 窗口Thread-2售出一张票。剩余票数:72 窗口Thread-0售出一张票。剩余票数:71 窗口Thread-1售出一张票。剩余票数:70 窗口Thread-2售出一张票。剩余票数:69 窗口Thread-0售出一张票。剩余票数:68 窗口Thread-1售出一张票。剩余票数:67 窗口Thread-2售出一张票。剩余票数:66 窗口Thread-0售出一张票。剩余票数:65 窗口Thread-1售出一张票。剩余票数:64 窗口Thread-2售出一张票。剩余票数:63 窗口Thread-0售出一张票。剩余票数:62 窗口Thread-1售出一张票。剩余票数:61 窗口Thread-2售出一张票。剩余票数:60 窗口Thread-0售出一张票。剩余票数:59 窗口Thread-1售出一张票。剩余票数:58 窗口Thread-2售出一张票。剩余票数:57 窗口Thread-0售出一张票。剩余票数:56 窗口Thread-1售出一张票。剩余票数:55 窗口Thread-2售出一张票。剩余票数:54 窗口Thread-0售出一张票。剩余票数:53 窗口Thread-1售出一张票。剩余票数:52 窗口Thread-2售出一张票。剩余票数:51 窗口Thread-0售出一张票。剩余票数:50 窗口Thread-1售出一张票。剩余票数:49 窗口Thread-2售出一张票。剩余票数:48 窗口Thread-0售出一张票。剩余票数:47 窗口Thread-1售出一张票。剩余票数:46 窗口Thread-2售出一张票。剩余票数:45 窗口Thread-0售出一张票。剩余票数:44 窗口Thread-1售出一张票。剩余票数:43 窗口Thread-2售出一张票。剩余票数:42 窗口Thread-0售出一张票。剩余票数:41 窗口Thread-1售出一张票。剩余票数:40 窗口Thread-2售出一张票。剩余票数:39 窗口Thread-0售出一张票。剩余票数:38 窗口Thread-1售出一张票。剩余票数:37 窗口Thread-2售出一张票。剩余票数:36 窗口Thread-0售出一张票。剩余票数:35 窗口Thread-1售出一张票。剩余票数:34 窗口Thread-2售出一张票。剩余票数:33 窗口Thread-0售出一张票。剩余票数:32 窗口Thread-1售出一张票。剩余票数:31 窗口Thread-2售出一张票。剩余票数:30 窗口Thread-0售出一张票。剩余票数:29 窗口Thread-1售出一张票。剩余票数:28 窗口Thread-2售出一张票。剩余票数:27 窗口Thread-0售出一张票。剩余票数:26 窗口Thread-1售出一张票。剩余票数:25 窗口Thread-2售出一张票。剩余票数:24 窗口Thread-0售出一张票。剩余票数:23 窗口Thread-1售出一张票。剩余票数:22 窗口Thread-2售出一张票。剩余票数:21 窗口Thread-0售出一张票。剩余票数:20 窗口Thread-1售出一张票。剩余票数:19 窗口Thread-2售出一张票。剩余票数:18 窗口Thread-0售出一张票。剩余票数:17 窗口Thread-1售出一张票。剩余票数:16 窗口Thread-2售出一张票。剩余票数:15 窗口Thread-0售出一张票。剩余票数:14 窗口Thread-1售出一张票。剩余票数:13 窗口Thread-2售出一张票。剩余票数:12 窗口Thread-0售出一张票。剩余票数:11 窗口Thread-1售出一张票。剩余票数:10 窗口Thread-2售出一张票。剩余票数:9 窗口Thread-0售出一张票。剩余票数:8 窗口Thread-1售出一张票。剩余票数:7 窗口Thread-2售出一张票。剩余票数:6 窗口Thread-0售出一张票。剩余票数:5 窗口Thread-1售出一张票。剩余票数:4 窗口Thread-2售出一张票。剩余票数:3 窗口Thread-0售出一张票。剩余票数:2 窗口Thread-1售出一张票。剩余票数:1 窗口Thread-2售出一张票。剩余票数:0 没有余票! 窗口Thread-0售出一张票。剩余票数:-1 没有余票! 窗口Thread-1售出一张票。剩余票数:-2 没有余票!
仍然会有超卖现象发生!
3.通知线程退出
有时候,我们需要不同的线程可以相互控制对方的运行
可以采用通知线程中止来解决此类问题,比如我们简单实现一个DEMO,实现主线程通知中止其他线程的效果:
/** * 通知线程中止 */ public class ThreadExit { public static void main(String[] args) throws InterruptedException { TTT ttt = new TTT(); ttt.start(); Thread.sleep(5000); // 主线程通知其他线程退出 ttt.setLoop(false); } } class TTT extends Thread { // 控制变量 private boolean loop = true; @Override public void run() { while (loop) { try { Thread.sleep(50); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("TTT线程正在运行..."); } } public void setLoop(boolean loop) { this.loop = loop; } }
TTT线程会运行5秒,随后由主线程通知退出🤖
4.解决超卖问题,线程同步机制
在多线程编程中,一些敏感数据不允许被多个线程同时访问,此时就可以使用同步访问技术,保证数据在同一时刻只能有一个线程访问,以保证数据的完整性
synchronized线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作🤖
上成品代码:
/** * 使用同步机制解决售票问题的超卖现象 */ public class TicketSalesResult { public static void main(String[] args) { SellTicketRes sellTicketRes = new SellTicketRes(); new Thread(sellTicketRes).start(); new Thread(sellTicketRes).start(); new Thread(sellTicketRes).start(); } } class SellTicketRes implements Runnable { private int ticketNum = 100; private boolean loop = true; /** * 使用synchronized实现线程同步,解决超卖 */ public synchronized void Sell() { if (ticketNum <= 0) { System.out.println("没有余票!"); loop = false; return; } // 休眠卖票 try { Thread.sleep(50); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("窗口" + Thread.currentThread().getName() + "售出一张票。" + "剩余票数:" + (--ticketNum)); } @Override public void run() { while (true) { if (loop == false) { break; } Sell(); } } }
结果分析:(完美解决超卖问题)
窗口Thread-0售出一张票。剩余票数:99 窗口Thread-0售出一张票。剩余票数:98 窗口Thread-0售出一张票。剩余票数:97 窗口Thread-0售出一张票。剩余票数:96 窗口Thread-0售出一张票。剩余票数:95 窗口Thread-0售出一张票。剩余票数:94 窗口Thread-0售出一张票。剩余票数:93 窗口Thread-0售出一张票。剩余票数:92 窗口Thread-0售出一张票。剩余票数:91 窗口Thread-0售出一张票。剩余票数:90 窗口Thread-0售出一张票。剩余票数:89 窗口Thread-0售出一张票。剩余票数:88 窗口Thread-0售出一张票。剩余票数:87 窗口Thread-0售出一张票。剩余票数:86 窗口Thread-0售出一张票。剩余票数:85 窗口Thread-0售出一张票。剩余票数:84 窗口Thread-0售出一张票。剩余票数:83 窗口Thread-0售出一张票。剩余票数:82 窗口Thread-0售出一张票。剩余票数:81 窗口Thread-0售出一张票。剩余票数:80 窗口Thread-2售出一张票。剩余票数:79 窗口Thread-2售出一张票。剩余票数:78 窗口Thread-2售出一张票。剩余票数:77 窗口Thread-2售出一张票。剩余票数:76 窗口Thread-2售出一张票。剩余票数:75 窗口Thread-2售出一张票。剩余票数:74 窗口Thread-2售出一张票。剩余票数:73 窗口Thread-2售出一张票。剩余票数:72 窗口Thread-2售出一张票。剩余票数:71 窗口Thread-1售出一张票。剩余票数:70 窗口Thread-1售出一张票。剩余票数:69 窗口Thread-1售出一张票。剩余票数:68 窗口Thread-1售出一张票。剩余票数:67 窗口Thread-1售出一张票。剩余票数:66 窗口Thread-1售出一张票。剩余票数:65 窗口Thread-1售出一张票。剩余票数:64 窗口Thread-1售出一张票。剩余票数:63 窗口Thread-1售出一张票。剩余票数:62 窗口Thread-1售出一张票。剩余票数:61 窗口Thread-1售出一张票。剩余票数:60 窗口Thread-1售出一张票。剩余票数:59 窗口Thread-1售出一张票。剩余票数:58 窗口Thread-1售出一张票。剩余票数:57 窗口Thread-1售出一张票。剩余票数:56 窗口Thread-1售出一张票。剩余票数:55 窗口Thread-1售出一张票。剩余票数:54 窗口Thread-1售出一张票。剩余票数:53 窗口Thread-1售出一张票。剩余票数:52 窗口Thread-1售出一张票。剩余票数:51 窗口Thread-1售出一张票。剩余票数:50 窗口Thread-1售出一张票。剩余票数:49 窗口Thread-1售出一张票。剩余票数:48 窗口Thread-1售出一张票。剩余票数:47 窗口Thread-1售出一张票。剩余票数:46 窗口Thread-1售出一张票。剩余票数:45 窗口Thread-1售出一张票。剩余票数:44 窗口Thread-1售出一张票。剩余票数:43 窗口Thread-1售出一张票。剩余票数:42 窗口Thread-2售出一张票。剩余票数:41 窗口Thread-2售出一张票。剩余票数:40 窗口Thread-2售出一张票。剩余票数:39 窗口Thread-2售出一张票。剩余票数:38 窗口Thread-2售出一张票。剩余票数:37 窗口Thread-2售出一张票。剩余票数:36 窗口Thread-2售出一张票。剩余票数:35 窗口Thread-2售出一张票。剩余票数:34 窗口Thread-2售出一张票。剩余票数:33 窗口Thread-2售出一张票。剩余票数:32 窗口Thread-2售出一张票。剩余票数:31 窗口Thread-2售出一张票。剩余票数:30 窗口Thread-2售出一张票。剩余票数:29 窗口Thread-2售出一张票。剩余票数:28 窗口Thread-2售出一张票。剩余票数:27 窗口Thread-2售出一张票。剩余票数:26 窗口Thread-2售出一张票。剩余票数:25 窗口Thread-2售出一张票。剩余票数:24 窗口Thread-2售出一张票。剩余票数:23 窗口Thread-2售出一张票。剩余票数:22 窗口Thread-2售出一张票。剩余票数:21 窗口Thread-2售出一张票。剩余票数:20 窗口Thread-2售出一张票。剩余票数:19 窗口Thread-2售出一张票。剩余票数:18 窗口Thread-2售出一张票。剩余票数:17 窗口Thread-2售出一张票。剩余票数:16 窗口Thread-0售出一张票。剩余票数:15 窗口Thread-0售出一张票。剩余票数:14 窗口Thread-0售出一张票。剩余票数:13 窗口Thread-0售出一张票。剩余票数:12 窗口Thread-0售出一张票。剩余票数:11 窗口Thread-0售出一张票。剩余票数:10 窗口Thread-0售出一张票。剩余票数:9 窗口Thread-0售出一张票。剩余票数:8 窗口Thread-0售出一张票。剩余票数:7 窗口Thread-2售出一张票。剩余票数:6 窗口Thread-2售出一张票。剩余票数:5 窗口Thread-2售出一张票。剩余票数:4 窗口Thread-2售出一张票。剩余票数:3 窗口Thread-2售出一张票。剩余票数:2 窗口Thread-2售出一张票。剩余票数:1 窗口Thread-2售出一张票。剩余票数:0 没有余票! 没有余票! 没有余票!