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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 黑马-张扬 中级黑马   /  2012-12-2 17:08  /  1460 人查看  /  4 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

下面这个例子是一个多线程买票的错误示例:

public class SaleTicketMutiThread implements Runnable {
int tickets = 100;
int temp = tickets;
boolean flag = true;
@Override
public void run() {
   while (flag) {
    if (tickets > 0) {
     try {
      Thread.sleep(30);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
     sale();
    } else {
     flag = false;
     System.out.println(Thread.currentThread().getName() + "卖光了");
    }
   }
}
public synchronized void sale() {
   tickets--;
   System.out.println(Thread.currentThread().getName() + " 已卖"
     + (temp - tickets) + "张,系统还剩" + tickets + "张票");
}
/**
   * @param args
   */
public static void main(String[] args) {
   SaleTicketMutiThread st = new SaleTicketMutiThread();
   new Thread(st, "一号窗口").start();
   new Thread(st, "二号窗口").start();
   new Thread(st, "三号窗口").start();
   new Thread(st, "四号窗口").start();
}
}

最后会运行出的结果会出现负数:
......
四号窗口 已卖99张,系统还剩1张票
一号窗口 已卖100张,系统还剩0张票
一号窗口卖光了
三号窗口 已卖101张,系统还剩-1张票
四号窗口 已卖102张,系统还剩-2张票
二号窗口 已卖103张,系统还剩-3张票

我的疑问:
我想问的是 一号窗口线程 取得了 共享变量tickets 的时候, 二、三、四号窗口线程也取得了tickets, 即使这时候一号窗口线程 调用了 sale 方法 对其进行 tickets -- 操作,   二、三、四号窗口线程取得了tickets还是先前的,没有执行tickets -- 操作 ;

评分

参与人数 1技术分 +1 收起 理由
奋斗的青春 + 1 神马都是浮云

查看全部评分

4 个回复

倒序浏览
public class SaleTicketMutiThread implements Runnable {
int tickets = 5;
int temp = tickets;
boolean flag = true;
@Override
public void run() {
    while (flag) {
            sale();
    }
}
public synchronized void sale() {
     if (tickets > 0) {
             try {
                   Thread.sleep(30);
                  } catch (InterruptedException e) {
                  e.printStackTrace();
                  }
             tickets--;
                System.out.println(Thread.currentThread().getName() + " 已卖"
                  + (temp - tickets) + "张,系统还剩" + tickets + "张票");
     } else {
      flag = false;
      System.out.println(Thread.currentThread().getName() + "卖光了");
     }
   
}
/**
    * @param args
    */
public static void main(String[] args) {
    SaleTicketMutiThread st = new SaleTicketMutiThread();
    new Thread(st, "一号窗口").start();
    new Thread(st, "二号窗口").start();
    new Thread(st, "三号窗口").start();
    new Thread(st, "四号窗口").start();
}
}

评分

参与人数 1技术分 +1 收起 理由
古银平 + 1 神马都是浮云

查看全部评分

回复 使用道具 举报
主要是你同步的代码问题,上面的if (tickets > 0) 判断也要写进同步代码块。否则现场判断时还是0之前的数据。
回复 使用道具 举报
else {
      flag = false;
      System.out.println(Thread.currentThread().getName() + "卖光了");
     }
这句话不被同步保护,当tickets《0时 每个线程都会打印一次。
回复 使用道具 举报
线程没有完全进行同步,else 里面的flag并不是对于所有的线程都同步啊,这个修改下,就行了。
package cn.itcast.Test;

public class ThreadTest3 {

        /**
         * @param args
         */
        public static void main(String[] args) {
                // TODO Auto-generated method stub
                 SaleTicketMutiThread st = new SaleTicketMutiThread();
                   new Thread(st, "一号窗口").start();
                   new Thread(st, "二号窗口").start();
                   new Thread(st, "三号窗口").start();
                   new Thread(st, "四号窗口").start();
        }
       
        //下面这个例子是一个多线程买票的错误示例:

}
class SaleTicketMutiThread implements Runnable {
        int tickets = 100;
        int temp = tickets;
        boolean flag = true;
        @Override
        public void run() {
           while (flag) {
           /* if (tickets > 0) {
             try {
              Thread.sleep(30);
             } catch (InterruptedException e) {
              e.printStackTrace();
             }
             sale();
            } else {
            // flag = false;
             System.out.println(Thread.currentThread().getName() + "卖光了");
            
           }*/
                   sale();
           }
        }
        public synchronized void sale() {
          
           if(tickets>0){
                   tickets--;
                   System.out.println(Thread.currentThread().getName() + " 已卖"
                     + (temp - tickets) + "张,系统还剩" + tickets + "张票");
           }
           else
                   flag=false;
          
        }
}

评分

参与人数 1技术分 +1 收起 理由
古银平 + 1 神马都是浮云

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马