A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© yangcy 中级黑马   /  2014-7-13 16:07  /  3843 人查看  /  10 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 yangcy 于 2014-7-13 16:40 编辑
  1. import java.util.ArrayList;
  2. import java.util.Iterator;
  3. import java.util.List;

  4. public class ThreadDemo {

  5.         /**
  6.          * 7、 编写三各类Ticket、SealWindow、TicketSealCenter分别代表票信息、售票窗口、售票中心。售票中心分配一定数量的票,
  7.          * 由若干个售票窗口进行出售,利用你所学的线程知识来模拟此售票过程。
  8.          *
  9.          */
  10.         public static void main(String[] args) {
  11.                 Thread t1 = new Thread(new SealWindow());
  12.                 t1.setName("1号售票窗口");
  13.                 Thread t2 = new Thread(new SealWindow());
  14.                 t2.setName("2号售票窗口");
  15.                 Thread t3 = new Thread(new SealWindow());
  16.                 t3.setName("3号售票窗口");
  17.                 Thread t4 = new Thread(new SealWindow());
  18.                 t4.setName("4号售票窗口");
  19.                 Thread t5 = new Thread(new SealWindow());
  20.                 t5.setName("5号售票窗口");
  21.                 t1.start();
  22.                 t2.start();
  23.                 t3.start();
  24.                 t4.start();
  25.                 t5.start();
  26.         }

  27. }

  28. class Ticket {
  29.         private int id;

  30.         public int getId() {
  31.                 return id;
  32.         }

  33.         public void setId(int id) {
  34.                 this.id = id;
  35.         }

  36. }

  37. class SealWindow implements Runnable {

  38.         @Override
  39.         public void run() {
  40.                 sellTicket();
  41.         }

  42.         public void sellTicket() {
  43.                 TicketSealCenter tsc = TicketSealCenter.getInstance();
  44.                 List<Ticket> tickets = tsc.getTickets();
  45.                 while (!tickets.isEmpty()) {
  46.                         Iterator<Ticket> it = tickets.iterator();
  47.                         Ticket ticket = it.next();
  48.                         System.out.println(Thread.currentThread().getName() + "...."
  49.                                         + "卖了一张票,id为" + "..." + ticket.getId());
  50.                         tickets.remove(ticket);
  51.                 }
  52.         }
  53. }

  54. // 只有一个售票中心,所以把它设置成单例
  55. class TicketSealCenter {
  56.         private static List<Ticket> tickets = new ArrayList<Ticket>();
  57.         private int ticketNum = 100;

  58.         private TicketSealCenter() {
  59.                 // 给每张票设置一个唯一的ID号
  60.                 setIdToTicket(tickets);
  61.         }

  62.         private static TicketSealCenter tsc = new TicketSealCenter();

  63.         // 提供一个公有方法,获取售票中心对象
  64.         public static TicketSealCenter getInstance() {
  65.                 return tsc;
  66.         }

  67.         private void setIdToTicket(List<Ticket> tickets2) {
  68.                 for (int i = 1; i <= ticketNum; i++) {
  69.                         Ticket ticket = new Ticket();
  70.                         ticket.setId(i);
  71.                         tickets.add(ticket);
  72.                 }
  73.         }

  74.         public List<Ticket> getTickets() {
  75.                 return tickets;
  76.         }

  77. }
复制代码
会出现线程卖的是同一张票。求分析并解决。多谢。

10 个回复

倒序浏览
票是共享资源,又有多个线程在操作,所以会出现线程安全问题,你需要在用迭代器取票的时候加锁,将票取完后释放锁。

评分

参与人数 2技术分 +1 黑马币 +10 收起 理由
HM汪磊 + 1 + 5 赞一个!
yangcy + 5 赞一个!

查看全部评分

回复 使用道具 举报 1 0
暗影流光 发表于 2014-7-13 16:12
票是共享资源,又有多个线程在操作,所以会出现线程安全问题,你需要在用迭代器取票的时候加锁,将票取完后 ...

加上锁之后还是有问题,程序停在那里了,死循环了貌似。求大神点拨。
回复 使用道具 举报
并且在拿到锁之后,还需再次判断集合是否为空,防止线程进入循环后再拿到锁的时候,集合已经为空
  1. while (!tickets.isEmpty()) {
  2.                         lock.lock();
  3.                         //线程拿到锁之后,需要重新判断集合是否为空,防止线程进入循环之后,拿到锁时,集合已经为空
  4.                         if (tickets.isEmpty()) {
  5.                                 //如果集合为空,跳出循环时,需要释放锁,防止在循环里面的其它线程,因为拿不到锁而无法结束循环
  6.                                 lock.unlock();
  7.                                 break;
  8.                         }
  9.                         Iterator<Ticket> it = tickets.iterator();
  10.                         Ticket ticket = it.next();
  11.                         System.out.println(Thread.currentThread().getName() + "...."
  12.                                         + "卖了一张票,id为" + "..." + ticket.getId());
  13.                         tickets.remove(ticket);
  14.                         lock.unlock();
  15.                 }
复制代码

评分

参与人数 2技术分 +2 黑马币 +10 收起 理由
HM汪磊 + 2 + 5 很给力!
yangcy + 5 赞一个!

查看全部评分

回复 使用道具 举报
暗影流光 发表于 2014-7-13 16:25
并且在拿到锁之后,还需再次判断集合是否为空,防止线程进入循环后再拿到锁的时候,集合已经为空
...

多谢啊。解决了。:)
回复 使用道具 举报
大神啊。膜拜下
回复 使用道具 举报
我写了一下,怎么票号是按照从1开始到100,一次递增的啊,不是乱的啊?
while (!tickets.isEmpty()) {
                    synchronized (tickets) {
                            if(tickets.isEmpty()){
                                                        break;
                                                }
                                                Iterator<Ticket> it = tickets.iterator();
                                                Ticket ticket = it.next();
                                               
                                                System.out
                                                                .println(Thread.currentThread().getName()
                                                                                + "...." + "卖了一张票,id为" + "..."
                                                                                + ticket.getId());
                                                tickets.remove(ticket);
                                        }
            }
回复 使用道具 举报
这个答案有帮助
回复 使用道具 举报
针对sellTicket()方法加个线程锁
回复 使用道具 举报
针对sellTicket()方法加个线程锁
回复 使用道具 举报
大神啊~~~膜拜
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马