黑马程序员技术交流社区

标题: 【急】求教多线程问题,老是一个线程完成 [打印本页]

作者: 不喝茶的陆羽    时间: 2013-6-7 23:02
标题: 【急】求教多线程问题,老是一个线程完成
本帖最后由 不喝茶的陆羽 于 2013-6-7 23:46 编辑

class Ticket{
        private static int ticketNum;

        public int getTicketNum() {
                return ticketNum;
        }

        public Ticket(int ticketNum){
                this.ticketNum=ticketNum;
        }
        public static  boolean available(){
                if(ticketNum>0){
                        return true;
                }
                else{
                        return false;
                }
        }
        public static  void sealTicket(String winName){               
                        System.out.println(winName+"-----恭喜您,您已完成票务购买-----");
                        System.out.println("还剩余"+(--ticketNum)+"张票");               
        }
}
class SealWindow implements Runnable {
        private String winName;
        private Ticket ticket;

        SealWindow(String winName,Ticket ticket){
                this.winName=winName;
                this.ticket=ticket;
        }
        public void run(){
                System.out.println("欢迎来到"+winName+"售票窗口,很高兴为您服务");
                synchronized(ticket){
                while(ticket.available()){
                                Ticket.sealTicket(winName);
                        }                                       
                }
                System.out.println("-----票已卖完,下次发售时间:明早8:00,欢迎届时购买-----");        
        }         
}        
public class Test7 {   //此处的Test7应该为TicketSealCenter,但是因为考试要求中的类名规范,特此说明

        public static void main(String[] args) {
                //售票中心 分配售票窗口 和总票数
                // 生产票 送到售票中心
                Ticket ticket = new Ticket(1000);
                //建立 3个售票窗口
                SealWindow sw1 = new SealWindow("售票窗口一",ticket);
                SealWindow sw2 = new SealWindow("售票窗口二",ticket);
                SealWindow sw3 = new SealWindow("售票窗口三",ticket);
               
                new Thread(sw2).start();
                new Thread(sw1).start();
                new Thread(sw3).start();
        }
}
急等各位大神回复啊~


作者: 不喝茶的陆羽    时间: 2013-6-7 23:20
真的急求啊,自己顶顶~
有赏金会不会有人呢?如果回答的好,我自己愿意送给好心人50金币....
作者: 神之梦    时间: 2013-6-7 23:28
本帖最后由 神之梦 于 2013-6-7 23:34 编辑

同步加在while里面
还有一点就是:
available方法没必要,虽然不影响结果,但是尽量简化代码
作者: 曹宇    时间: 2013-6-7 23:37
首先,我如果你老师 这题满分100就算你写对了 我也会只给你80分。

写代码,并且是发代码寻求帮助,最基本的就是要写上注释,每一步是做什么的,并且在发帖提问的时候,尽量在代码之前先将你的问题的情况具体说明一下,别人知道你的问题之后在根据你的问题去针对性的分析代码。。。。。。

因为很多人论坛浏览帖子回答问题是没有耐心去分析你代码的逻辑关系的,人们大多是大致扫一下,看一下有没有明显的逻辑关系错误。

我看你这个代码就很头痛,有注释,但是不多,主要的逻辑关系还是要分析,所以我需要一点点分析你的逻辑关系,你的变量是想做什么事情,算法是什么意思。。。

所以,记住,良好的写注释的习惯是必备的。以后无论是面试,还是自己回顾自己的代码,都是必不可少的。

------------------------------------------------------------------------------------------------

好了,说的都是题外话。

输出是什么样的?
一直运行的线程是哪一个? 多运行几次是否还是这个线程一直运行,或者是变成了别的线程一直运行?

你代码我没有细看,我一开始是以为没有装入同步锁,后来仔细一看发现有同步。

我想你可以尝试一下,给每个线程添加一个sleep方法,睡个10毫秒那样,在看一看别的线程是否会运行,或者给票的数量定多一点,让程序多运行一下。

因为cpu可能在运行一个线程的时候就已经卖完票了,所以另外的线程还没等待到执行权程序就结束了。
作者: 不喝茶的陆羽    时间: 2013-6-7 23:41
先回下,然后再看回复,自己发现了,我把循环所在同步里了,这样一旦进去了同步,就会一直到循环结束....看看有没有人给出解决代码....
作者: 不喝茶的陆羽    时间: 2013-6-7 23:43
曹宇 发表于 2013-6-7 23:37
首先,我如果你老师 这题满分100就算你写对了 我也会只给你80分。

写代码,并且是发代码寻求帮助,最基本 ...

谢谢你的建议
作者: 不喝茶的陆羽    时间: 2013-6-7 23:44
神之梦 发表于 2013-6-7 23:28
同步加在while里面
还有一点就是:
available方法没必要,虽然不影响结果,但是尽量简化代码 ...

谢谢,虽然说得很简练,但是还是履行我的承诺
作者: 曹宇    时间: 2013-6-7 23:44
  1. synchronized(ticket){
  2.                 while(ticket.available()){
  3.                                 Ticket.sealTicket(winName);
  4.                         }                                       
  5.                 }
复制代码
注意这一段代码。

while循环判断票数是否为0 有票就继续卖。

那么 如果线程1 先执行 那么线程1 在卖票 因为你加入的有同步锁 所以其他线程根本就进不来,只能眼巴巴的看着线程1 一直将票卖完  然后线程1循环结束

这时候其他线程才能进入同步锁执行,而当它们进入的时候,就傻眼了 ,因为线程1这个混蛋已经全部把票卖完了,所以

你的程序最后总有3句  票已经卖完 请下次再买。。

问题就出在这里,解决方案你自己想一想,我要继续给电脑做系统了。。。等会做完系统后在来看看,要是不知道的话在回复问我把。
作者: 不喝茶的陆羽    时间: 2013-6-7 23:45
神之梦 发表于 2013-6-7 23:28
同步加在while里面
还有一点就是:
available方法没必要,虽然不影响结果,但是尽量简化代码 ...

抱歉,我才 知道,最多只能给30分,不好意思了....
作者: 不喝茶的陆羽    时间: 2013-6-7 23:45
曹宇 发表于 2013-6-7 23:37
首先,我如果你老师 这题满分100就算你写对了 我也会只给你80分。

写代码,并且是发代码寻求帮助,最基本 ...

谢谢你的建议
作者: 神之梦    时间: 2013-6-7 23:52
不喝茶的陆羽 发表于 2013-6-7 23:45
抱歉,我才 知道,最多只能给30分,不好意思了....

没事,我回帖一是希望可以帮助哥们,二是巩固自己的知识,对于金币或者技术分都无所谓了(确实我已经满了-_-||),三是通过交流可以多认识些朋友,同时也传达一种乐于去帮助别人解决问题的精神(无关技术分而为之的)
作者: 曹宇    时间: 2013-6-8 00:26
系统做好了,。。。。
在循环部分改成这样
  1. while(true)
  2.                                 {
  3.                                                 synchronized(ticket)
  4.                                                 {
  5.                                                         if(ticket.available())
  6.                                                         {
  7.                                                                 Ticket.sealTicket(winName);
  8.                                                                
  9.                                                         }
  10.                                                         else
  11.                                                                 break;
  12.                         }                                       
  13.                 }
复制代码
首先 同步移动到循环之内,这样才会让别的线程有机会

判断也要在同步之内判断。

因为在同步外判断,当一个线程判断票数为1  好的 满足,然后还没进去同步 另外一个线程抢了CPU然后判断 哟 是1阿 满足,然后 它进去了,它卖完了
释放CPU  然后那个被抢的悲催线程获得了执行权  

因为他判断过了 是1满足 所以直接就进去了,所以就会打印出  票卖完  剩余票数 -1     -1阿-1阿-1阿 ,  哪个火车站敢这样打印出来,还不叫人拍照发送到糗事百科上去给人乐阿。。

所以 判断要在同步内判断,也就是说每一个进入同步的线程 都先判断 满足在搞  不满足直接break 没票了,哥们你逃票得了。。
作者: 曹宇    时间: 2013-6-8 00:32
一开始我以为搞错了 怎么还是一直一个线程在卖阿,我就蛋疼,怎么分析也没错,后来多运行几次,突然发现。

不对阿,

如果问题没解决只能一个线程在玩单机游戏,那凭什么会是 售票窗口1 在卖票呢。

因为我分析了一下你的主函数
  1. new Thread(sw2).start();
  2.                 new Thread(sw1).start();
  3.                 new Thread(sw3).start();
复制代码
你是先创建的线程2 就是售票窗口2  如果问题没解决那么永远是窗口2在玩单机游戏,凭什么1能卖盘,1只能等2卖完才能打印个 苦逼的票已经卖完。

然后 多运行了几次,发现了窗口1  立刻 ctrl+c  然后就发现了。
  1. 程序运行输出:

  2. 还剩余99989张票
  3. 售票窗口二-----恭喜您,您已完成票务购买-----
  4. 还剩余99988张票
  5. 售票窗口二-----恭喜您,您已完成票务购买-----
  6. 还剩余99987张票
  7. 售票窗口二-----恭喜您,您已完成票务购买-----
  8. 还剩余99986张票
  9. 售票窗口一-----恭喜您,您已完成票务购买-----
  10. 还剩余99985张票
  11. 售票窗口一-----恭喜您,您已完成票务购买-----
  12. 还剩余99984张票
  13. 售票窗口一-----恭喜您,您已完成票务购买-----
  14. 还剩余99983张票
  15. 售票窗口一-----恭喜您,您已完成票务购买-----
复制代码
总算让我逮到了。。。。

我还蛋疼的以为代码错误呢。。。。


好吧,可能是CPU运行速度过快,或者过慢?


作者: 不喝茶的陆羽    时间: 2013-6-8 01:55
曹宇 发表于 2013-6-8 00:32
一开始我以为搞错了 怎么还是一直一个线程在卖阿,我就蛋疼,怎么分析也没错,后来多运行几次,突然发现。
...

谢谢啦~辛苦了。
作者: 不喝茶的陆羽    时间: 2013-6-8 01:55
曹宇 发表于 2013-6-8 00:32
一开始我以为搞错了 怎么还是一直一个线程在卖阿,我就蛋疼,怎么分析也没错,后来多运行几次,突然发现。
...

谢谢啦~辛苦了。
作者: 不喝茶的陆羽    时间: 2013-6-8 01:59
曹宇 发表于 2013-6-8 00:26
系统做好了,。。。。
在循环部分改成这样首先 同步移动到循环之内,这样才会让别的线程有机会

这个虽然解决了同步问题,但是不会造成死循环吗?虽然不满足循环里面代码但是它会一直转啊?
作者: 不喝茶的陆羽    时间: 2013-6-8 02:00
while(true)
                                {
                                                synchronized(ticket)
                                                {
                                                        if(ticket.available())
                                                        {
                                                                Ticket.sealTicket(winName);
                                                               
                                                        }
                                                        else
                                                                break;
                        }                                       
                }
虽然结果出来了,但是线程还是在一直运作啊...一直在循环
作者: 曹宇    时间: 2013-6-8 12:12
不喝茶的陆羽 发表于 2013-6-8 02:00
while(true)
                                {
                                                synch ...

不会把,我刚又试了一次,
我把你发问题的源代码复制进编辑器,又把修改的while循环覆盖原代码的循环
不会死循环阿,卖完就结束了.

从代码上分析,循环内部 第一步就判断 当卖完票后,判断不会满足 就会执行break 跳出的。。

你再看看你代码,是否有什么地方能够是的程序无法跳出循环


作者: 不喝茶的陆羽    时间: 2013-6-8 13:32
曹宇 发表于 2013-6-8 12:12
不会把,我刚又试了一次,
我把你发问题的源代码复制进编辑器,又把修改的while循环覆盖原代码的循环
不 ...

这个循环,你不是把判断值设为true了吗?那又怎么会卖完就退出呢?
作者: 不喝茶的陆羽    时间: 2013-6-8 13:33
疑问就是while(true){
            break;
}是死循环吗?
作者: 不喝茶的陆羽    时间: 2013-6-8 13:34
曹宇 发表于 2013-6-8 12:12
不会把,我刚又试了一次,
我把你发问题的源代码复制进编辑器,又把修改的while循环覆盖原代码的循环
不 ...

有一个新问题,如果有时间,希望能解答下~http://bbs.itheima.com/thread-55111-1-1.html
作者: 曹宇    时间: 2013-6-8 16:53
不喝茶的陆羽 发表于 2013-6-8 13:33
疑问就是while(true){
            break;
}是死循环吗?

不是的。。

whie(true)
{

}

这样是死循环

while(true)
{
  循环中加入判断 如果什么什么的  就 break;
  break;就是跳出循环结束循环的语句。
}
作者: 不喝茶的陆羽    时间: 2013-6-8 17:19
曹宇 发表于 2013-6-8 16:53
不是的。。

whie(true)

对,我和continue混了
作者: 不喝茶的陆羽    时间: 2013-6-8 17:26
神之梦 发表于 2013-6-7 23:52
没事,我回帖一是希望可以帮助哥们,二是巩固自己的知识,对于金币或者技术分都无所谓了(确实我已经满了 ...

希望学长或是学姐有时间的话能解答下我的这个问题,麻烦了~
http://bbs.itheima.com/thread-55111-1-1.html




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