黑马程序员技术交流社区

标题: 多线程的一个运行时小问题:为什么会多次出现同一张? [打印本页]

作者: libra    时间: 2013-11-21 07:22
标题: 多线程的一个运行时小问题:为什么会多次出现同一张?
package day11.thread;
/**
* 简单的售票程序。多个窗口同时售票。
* 注意给所有线程公共的数据tick用static修饰。
* 注意安全问题:使用Thread.sleep()可以有效检查。tick有同一张或者0、-1号等问题。
* 为什么会多次出现同一张呢?????
* 原因:多条语句操作同一个线程共享的数据时,一个线程对多条语句只执行了一部分。此时另一个线程参与进来执行。
* 解决方案:同步代码块。
* 同步的前提:两个以上的线程;多个线程使用同一个锁。
* @author Administrator
*
*/
public class ThreadDemo3 {
public static void main(String[] args) {
  Ticket t1 = new Ticket();
  Ticket t2 = new Ticket();
  Ticket t3 = new Ticket();
  
  t1.start();
  t2.start();
  t3.start();
}
}
class Ticket extends Thread {

// private static Object obj = new Object();
private static int tick = 100;

public void run() {
  while(true) {
//   synchronized(obj) {
    if(tick > 0) {
     try {
      Thread.sleep(10);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
     System.out.println(this.getName() + " sale: " + tick--);
    }
//   }
  }
}
}

作者: 何丛    时间: 2013-11-21 07:32
楼主,你想问什么?

作者: libra    时间: 2013-11-21 08:35
下边是我一次运行时输出的一段结果:100号票居然被卖了3次,
98号票被卖了两次。
Thread-0 sale: 100
Thread-2 sale: 100
Thread-1 sale: 100
Thread-2 sale: 99
Thread-0 sale: 98
Thread-1 sale: 98
作者: hubby    时间: 2013-11-21 08:55
我只能说lz可以继续往下看视频。。。我估计楼主的意思是为什么不加同步多线程会出现重复。
简单解释一下就是cpu运行机制,cpu在某一个固定的瞬间只运行一个线程,有多个线程时cpu快速切换“速度可以用刷刷刷形容。。”但是你的多线程共同操作的代码并不是一句话就完事的,而是好几句话,可能线程1还没读完那个共同操作的代码线程2就开始读共同代码了。就是说没有加锁就不能保证一个线程把共同使用的代码块一次性读完,就会导致出现重复的情况。。。有点罗嗦了,但是希望楼主能明白
作者: libra    时间: 2013-11-21 09:55
hubby 发表于 2013-11-21 08:55
我只能说lz可以继续往下看视频。。。我估计楼主的意思是为什么不加同步多线程会出现重复。
简单解释一下就 ...

我不知道将System.out.println(this.getName() + " sale: " + tick--);
拆成tick--;System.out.println(this.getName() + " sale: " + tick);
会有什么不同效果。就说这目前没有拆开的情况,虽然有多个线程异步执行,也就是他们可能都打印100号票,但是打完之后tick应该--多次啊,那就不应该再打印99号票了。也不是说绝对没有,例如t1和t2都将打印100号票了,t1先打印并执行到要打印下一张即99号票。然后此时应该就有多次打印100号票接着还打印99号票的情况。但是发现这里不会出现没有打印的票,即我说的两次打印100号,可能就不再打印99号票的情况。因为--两次,所以下一次应该直接打印98号票。
作者: 够了没有    时间: 2013-11-21 11:31
首先楼主你的代码中你把同步注释掉了,因此出现了多次卖出100号的情况。

代码一:System.out.println(this.getName() + " sale: " + tick--);

代码二:tick--;System.out.println(this.getName() + " sale: " + tick);

然后我跟你讲下我对以上代码一和代码二的理解吧:

假如tick的值是100,

代码一是:先把tick=100打印,再--变成tick=99留给下一次用;

代码二是:tick本来是100的,但是先--变成99了,然后打印的tick当然就是99了。





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2