黑马程序员技术交流社区
标题:
多线程第一种方式中的卖票中的小问题
[打印本页]
作者:
贺靖轩
时间:
2013-4-12 11:00
标题:
多线程第一种方式中的卖票中的小问题
问题:
1.为什么 Thread-0end-----97 已经输出了,后面还要输出 end
2.为什么 Thread-0end-----97 已经输出了,意味着票全部售出,为什么不是 Thread-0end-----100?
码:
public class TicketTest extends Thread
{
private static int tick=100;
static int count=0;
public void run()
{
while(true)
{
if(tick>0)
{
System.out.println(currentThread().getName()+"---"+tick--);
count++;
}
else
{
System.out.println(currentThread().getName()+"end-----"+count);
break;
}
}
}
public static void main(String[] args)
{
TicketTest t1=new TicketTest();
TicketTest t2=new TicketTest();
TicketTest t3=new TicketTest();
TicketTest t4=new TicketTest();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
复制代码
截取关键部分的输出语句:
Thread-0---10
Thread-0---9
Thread-0---8
Thread-0---7
Thread-0---6
Thread-0---5
Thread-0---4
Thread-0---3
Thread-0---2
Thread-0---1
Thread-0end-----97
Thread-3---16
Thread-3end-----98
Thread-1---17
Thread-1end-----99
Thread-2---13
Thread-2end-----100
问题:
1.为什么 Thread-0end-----97 已经输出了,后面还要输出 end
2.为什么 Thread-0end-----97 已经输出了,意味着票全部售出,为什么不是 Thread-0end-----100?
作者:
杨冉
时间:
2013-4-12 11:39
本帖最后由 杨冉 于 2013-4-12 12:09 编辑
这是因为你没有加锁来进行线程的同步。所以是不安全的,不安全的表现就像你所说的这样了,会出现输出错乱的情况。
分析你这个输出结果发生的原因就是,你这四个线程操作的都是同样的资源(tick和count)。线程在抢占CPU资源的时候,没有将一整段本该完整执行的代码执行完(比如刚刚判断了if语句正要执行输出语句时)就被别的线程抢占了CPU资源,而自己则让出了资源,当这个线程重新获取到资源时,本应重新判断的语句没有判断就从上次没执行完的地方继续执行了(比如现在共享资源已经改变,if语句本应判断失败,但却没有判断,而是直接执行了上次没有执行的输出语句),这样就发生了共享数据的错误,出现不到100就end也就不奇怪了。
可以尝试这样加入锁:
import java.util.concurrent.locks.*;
public class TicketTest extends Thread {
private Lock lock = new ReentrantLock();
private static int tick=100;
static int count=0;
public void run() {
while(true) {
lock.lock();
try {
if(tick>0) {
System.out.println(currentThread().getName()+"---"+tick--);
count++;
}
else {
System.out.println(currentThread().getName()+"end-----"+count);
break;
}
}finally {
lock.unlock();
}
}
}
public static void main(String[] args)
{
TicketTest t1=new TicketTest();
TicketTest t2=new TicketTest();
TicketTest t3=new TicketTest();
TicketTest t4=new TicketTest();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
复制代码
作者:
贺靖轩
时间:
2013-4-12 11:41
是不是可以换个理解方式。
对于Q1,Thread-0end-----97 已经输出了,就意味着此案例中的票确实是已经全部卖完了,tick确实是已经小于0了,但是是对于该窗口而言,因为另外3个也在进行着这个动作(TICK--),它所需要做的仅仅是打印自身所能涉及到的状态。对于票数售空,是其可以接触的内容;但是总票数在其调用结束后,却是另外三个线程需要关心的问题。
对于Q2,承接Q1中的思路。对于4线程各自来说,此时票数确实已经为0了,但是由于对CPU的资源的抢占,以及调用输出命令的延迟,使得一些没来得及输出的语句也产生了变化 ?
感觉好牵强,求正解。
作者:
张先龙
时间:
2013-4-12 11:46
本帖最后由 张先龙 于 2013-4-12 11:52 编辑
看来你没有理解多线程的意思啊
第一个问题:
你一共启动了四个线程,四个线程时并发执行的 。Thread-0end-----97 已经输出,说明该线程执行到这里时其实票已经卖完了,Thread0线程结束后,还有其他线程输出end ,是因为这四个程序是并发执行的,交替获得Cpu执行权,可能的原因是其他的线程例如Thread-2已经在Thread-0end-----97 之前执行过,将票已经卖完,还没有执行到输出语句那里就被Thread-0抢夺了CPU执行权,这时Thread-0进来执行时判断票已经卖完了,符合end的条件 ,结束。同时Thread2被唤醒,继续执行,之前未完成的部分执行完,所以会在Thread-0end-----97 输出之后还在输出。就是这个道理。
第二个问题其实的答案和第一个的原理其实是一样的。
作者:
贺靖轩
时间:
2013-4-12 11:58
恩 线程安全刚看的 才反应过来。
操作的都是同样的资源(tick和count)。线程在抢占CPU资源的时候,没有将一整段本该完整执行的代码执行完(比如刚刚判断了if语句正要执行输出语句时)就被别的线程抢占了CPU资源,而自己则让出了资源,当这个线程重新获取到资源时,本应重新判断的语句没有判断就从上次没执行完的地方继续执行了(比如现在共享资源已经改变,if语句本应判断失败,但却没有判断,而是直接执行了上次没有执行的输出语句),这样就发生了共享数据的错误,出现不到100就end也就不奇怪了。这个是理论。
你一共启动了四个线程,四个线程时并发执行的 Thread-0end-----97 已经输出,说明该线程执行到这里时其实票已经卖完了,线程结束,后面还输出end 是因为这四个程序是并发执行的,交替获得Cpu执行权,可能的原因是其他的线程例如Thread-2已经在Thread-0end-----97 之前执行过,将票已经卖完,但是被冻结,还没有执行到输出语句那里就被Thread-0抢夺CPU执行权,所以Thread-0进来执行是判断票已经卖完了,符合end的条件 ,结束。这时Thread2被唤醒,继续执行,所以会在Thread-0end-----97 输出之后还在输出。这个是实际。
归根结底是线程安全问题。
可参考
黑马程序员_毕向东_Java基础视频教程第11天-09-多线程(多线程的安全问题).avi
作者:
想学跑的猪
时间:
2013-4-12 12:07
你好,你这段代码是典型的多线程例子,在张孝祥老师的教学视频中有讲过。代码中一共有创建了四个线程,这四个线程的运行是不安全的,或者说他们不同步,出现这种,应该将if..else放到synchronized(str){}中。这样线程才会安全
作者:
打工人
时间:
2013-4-12 23:16
如果问题未解决,请继续追问,如果没有问题了,请将帖子分类 改为“已解决”,谢谢
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2