首页 > 代码库 > 多线程售票模型
多线程售票模型
上次Java实验课就写了一次,但是比较简单,这里再好好写一下
这里用集合类LinkList来存储车票
注意线程是抢占式时的,虽然在出票的时候是一个个出的,但是在Sysout.out.println()的时候被其他线程抢占,所以输出可能不是顺序的,这里用sleep方法之后就顺序输出了,为什么?
一般不用加sleep,因为后台出票的时候确实是一个个按照顺序出的。只是在打印的时候抢占了。
package com.ticket.thread;import java.util.LinkedList;import com.sun.org.apache.xalan.internal.xsltc.compiler.sym;/** * 带销售的车票 * * @author hwyou * */public class Ticket { // 所有的车票(容器) LinkedList<Integer> list = new LinkedList<>(); /** * * @param size * 车票的数量 */ public Ticket(int size) { for(int i = 1; i <= size; i ++) { list.add(i); } System.out.println(list); } //同步关键字,其他线程在当前线程没有结束之前是不能访问的 //"试衣间",对当前衣服在试衣间试衣服的时候其他人不能访问 public int sell() throws NoTicketException {// int t = list.getFirst(); //异常,对正常流程的中断 if(list.size()==0) { throw new NoTicketException(); } synchronized(list) { int t = list.removeFirst(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } return t; } } public void show() { System.out.println("剩余" + list); } }
这里加synchronized关键字,同步化之后,避免了多个线程访问同一张票,上个写法没有很体现出来,我们这样写,再用sleep放大,就提现了synchronized重要了。
有问题的写法:
package com.ticket.thread;import java.util.LinkedList;import com.sun.org.apache.xalan.internal.xsltc.compiler.sym;/** * 带销售的车票 * * @author hwyou * */public class Ticket { // 所有的车票(容器) LinkedList<Integer> list = new LinkedList<>(); /** * * @param size * 车票的数量 */ public Ticket(int size) { for(int i = 1; i <= size; i ++) { list.add(i); } System.out.println(list); } // 同步关键字,其他线程在当前线程没有结束之前是不能访问的 // "试衣间",对当前衣服在试衣间试衣服的时候其他人不能访问 public int sell() throws NoTicketException { int t = list.getFirst(); // 异常,对正常流程的中断 if (list.size() == 0) { throw new NoTicketException(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } list.removeFirst(); return t; } public void show() { System.out.println("剩余" + list); } }
因为在实际项目中,取票和出票中间确实可能有其他代码,其他操作,没有同步,就可能出这种错误
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
pool-1-thread-1开放
pool-1-thread-2开放
pool-1-thread-3开放
pool-1-thread-4开放
pool-1-thread-5开放
pool-1-thread-1售出1
pool-1-thread-4售出1
pool-1-thread-2售出1
pool-1-thread-3售出1
pool-1-thread-5售出1
pool-1-thread-3售出4
pool-1-thread-1售出4
pool-1-thread-4售出4
pool-1-thread-2售出4
pool-1-thread-5售出4
pool-1-thread-1售出6
pool-1-thread-2售出6
pool-1-thread-3售出6
pool-1-thread-4售出6
pool-1-thread-5售出7
pool-1-thread-3售出10
pool-1-thread-2售出10
pool-1-thread-4售出10
pool-1-thread-1售出10
pool-1-thread-5售出11
pool-1-thread-1售出14
pool-1-thread-3售出14
pool-1-thread-2售出14
pool-1-thread-4售出14
pool-1-thread-5售出15
pool-1-thread-5售罄
pool-1-thread-4售出19
pool-1-thread-1售罄
pool-1-thread-3售罄
pool-1-thread-2售罄
pool-1-thread-4售罄
一些票因为线程访问同一张票也减减,所以直接在后台就没了,前端打印自然也没有显示
非线程池写法:
package com.ticket.thread;/** * 自定义一个线程(售票窗口) * @author Administrator * */public class TicketOffice extends Thread { /** * 要销售的车票(引用) */ Ticket ticket; /** * 创建(初始化)售票窗口 * @param ticket * 待销售的车票 * @param name * 窗口名称 */ public TicketOffice(Ticket ticket, String name) { this.ticket = ticket; setName(name); } @Override public void run() { // TODO Auto-generated method stub super.run(); //售票 System.out.println(getName()+ "开放"); while (true) { try { int t = ticket.sell(); System.out.println(getName() + "售出:" + t); } catch (NoTicketException e) { // TODO Auto-generated catch block// e.printStackTrace(); System.out.println(getName()+"售罄"); break; } } System.out.println("关闭"); }}
线程池写法:
package com.ticket.thread;public class SaleTask implements Runnable{ Ticket ticket; public SaleTask(Ticket ticket) { this.ticket = ticket; } @Override public void run() { System.out.println(Thread.currentThread().getName()+"开放"); while(true) { try { int t = ticket.sell(); System.out.println(Thread.currentThread().getName() + "售出" + t); } catch (Exception e) { System.out.println(Thread.currentThread().getName() +"售罄"); break; } } } }
自定义异常类:
package com.ticket.thread;/** * 消息对象(信号) * @author Administrator * */public class NoTicketException extends Exception{ }
入口:
package com.ticket.thread;import java.util.concurrent.Executor;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class App { public static void main(String[] args) { //车票 Ticket ticket = new Ticket(20); // //创建窗口// TicketOffice office1 = new TicketOffice(ticket, "窗口一");// TicketOffice office2 = new TicketOffice(ticket, "窗口二");// TicketOffice office3 = new TicketOffice(ticket, "窗口三"); //ExecutorService是一个对象,容器,装线程的池子 ExecutorService pool = Executors.newFixedThreadPool(5); for(int i = 0; i < 5; i++) { pool.execute(new SaleTask(ticket)); } pool.shutdown();// office1.start();// office2.start();// office3.start(); }}
多线程售票模型