黑马程序员技术交流社区

标题: 5线程抢红包的代码实现求助 [打印本页]

作者: 水月灬清影    时间: 2016-8-19 19:05
标题: 5线程抢红包的代码实现求助
今天在论坛里看见这么一个题,他发的代码是错的,帖子还是仅作者可见……自己做了半天也没做出来,线程间通讯有问题,我贴一下题目,和自己做的代码,求前辈高人给看一下
/**
* 模拟抢红包过程,生成5个红包(金额是随机生成的,范围在1-10元之间)
* 创建5个线程代表5个人,然后让这5个人去抢这5个红包,每次抢红包需要300ms的时间,
*  在控制台打印出 (xxx抢了xxx元)
* (不限定每人抢的次数并且抢到红包后还可以接着抢,每次生成一个红包)
*
*@author
*
*/
作者: 水月灬清影    时间: 2016-8-19 19:09
本帖最后由 水月灬清影 于 2016-8-19 19:12 编辑

[Java] 纯文本查看 复制代码

//测试类
public class BonusDemo {
        public static void main(String[] args) {
                Bonus bon=new Bonus();
                SetThread st=new SetThread(bon);
                GetThread gt=new GetThread(bon);
               
                 Thread t0= new Thread(st);
         t0.setName("红包");
                 Thread t1 = new Thread(gt);
         t1.setName("1号");
         Thread t2 = new Thread(gt);
         t2.setName("2号");
         Thread t3 = new Thread(gt);
         t3.setName("3号");
         Thread t4 = new Thread(gt);
         t4.setName("4号");
         Thread t5 = new Thread(gt);
         t5.setName("5号");
        
         t0.start();
         t1.start();
         t2.start();
         t3.start();
         t4.start();
         t5.start();
        }
}


import java.util.Random;
//红包资源类
public class Bonus {
        private static int count=5;
        private static int bonus;
        private boolean flag;

        public synchronized void set(){
                if(this.flag==true){
                        try {
                                this.wait();
                        } catch (InterruptedException e) {
                               e.printStackTrace();
                        }
                }
                if(count>0){
                        Random r=new Random();
                        bonus=r.nextInt(10)+1;
                        count--;
                        System.out.println("红包已生成");
                        
                }
                this.flag=true;
                this.notify();
        }
        
        public synchronized void get(){
                if(this.flag==false){
                        try {
                                this.wait();
                        } catch (InterruptedException e) {
                        e.printStackTrace();
                        }
                }
               
                System.out.println(Thread.currentThread().getName()+bonus+"元");
                try {
                        Thread.sleep(300);
                } catch (InterruptedException e) {
                      e.printStackTrace();
                }
               
                this.flag=false;
                this.notify();
        }
}


public class SetThread implements Runnable {
        private static int count=5;
        private Bonus bon;
        public SetThread(Bonus bon) {
                this.bon=bon;
        }

        public void run() {
                while(count>0){
                        bon.set();
                        count--;
                }

        }

}


public class GetThread implements Runnable {
        private static int count=5;
        private Bonus bon;
        public GetThread(Bonus bon) {
                this.bon=bon;
        }
        public void run() {
                while(count>0){
                        count--;
                        bon.get();
                }
               
        }

}


作者: wyq0627java11    时间: 2016-8-19 19:34
public class Test02 implements Runnable {

        Random ra = new Random();
        int i = 0;
        int[] arr = { ra.nextInt(10) + 1, ra.nextInt(10) + 1, ra.nextInt(10) + 1,
                        ra.nextInt(10) + 1, ra.nextInt(10) + 1 };
        Object obj = new Object();

        public void run() {
                while (true) {
                        synchronized (obj) {
                                if (i < 5) {
                                        try {
                                                Thread.sleep(300);
                                        } catch (InterruptedException e) {

                                                e.printStackTrace();
                                        }
                                        System.out.println(Thread.currentThread().getName() + "抢了"
                                                        + arr[i++] + "元");

                                } else {
                                        break;
                                }
                        }
                }
        }

}

测试
public class Test2 {
public static void main(String[] args) {
        Test02 t = new Test02();
        Thread p1 = new Thread(t,"小明");
        Thread p2 = new Thread(t,"小亮");
        Thread p3 = new Thread(t,"小强");
        Thread p4 = new Thread(t,"小红");
        Thread p5 = new Thread(t,"小花");
       
        p1.start();
        p2.start();
        p3.start();
        p4.start();
        p5.start();
       
}
}


作者: 水月灬清影    时间: 2016-8-19 20:26
wyq0627java11 发表于 2016-8-19 19:34
public class Test02 implements Runnable {

        Random ra = new Random();

题目要求是抢一个,生成一个……
作者: 马蚁牙黑    时间: 2016-8-19 23:33
我是来看楼主的答案的,好牛的样子,目前还没搞懂
作者: lbx95272006    时间: 2016-8-25 01:21
水月灬清影 发表于 2016-8-19 19:09
[mw_shl_code=java,true]
//测试类
public class BonusDemo {

你代码写得很好, 你把flag 判断语句的if 改成while 就可以了, 我还想问下你 你红包类的get 方法中
while(count>0){
      count--

}
作者: lbx95272006    时间: 2016-8-25 01:22
本帖最后由 lbx95272006 于 2016-8-25 01:24 编辑
水月灬清影 发表于 2016-8-19 19:09
[mw_shl_code=java,true]
//测试类
public class BonusDemo {

你代码写得很好, 你把flag 判断语句的if 改成while 就可以了, 我还想问下你 你抢红包类的get 方法中
while(count>0){
      count--
      b.get();
}
我试了下,count--放在方法前和放在方法后是有区别的,我想问下你,为什么会这样
作者: 水月灬清影    时间: 2016-8-25 08:21
谢谢!但并不是if,while的问题,是单生产者多消费者的问题,我的代码如果注释掉线程2-5,实现单生产者单消费者是没问题的。count用于计数5次,你说的有区别是什么区别?该不是线程随机性的区别吧…………
作者: aabbcc2    时间: 2016-8-25 10:31
求解求解求解
作者: lbx95272006    时间: 2016-8-25 11:44
我试过了,把你的程序的if 改成 while 就可以了
作者: lbx95272006    时间: 2016-8-25 11:46
问题出在notify() 这个方法,我把你的notify()方法也改了下,改成notifyAll()  前面的方法每次只唤醒一个线程,如果唤醒的线程是同伴,那么同伴就会逃脱if标记的判断,所以会出现多人抢到同一个红包,改成while 就是为了重复判断if标记
作者: 水月灬清影    时间: 2016-8-25 12:38
本帖最后由 水月灬清影 于 2016-8-25 12:55 编辑
lbx95272006 发表于 2016-8-25 11:46
问题出在notify() 这个方法,我把你的notify()方法也改了下,改成notifyAll()  前面的方法每次只唤醒一个线 ...

!!!我把 if 改成 while,notify 改成 notifyAll 确实是实现了一个红包只有一个人抢到,但是题目要求的是一个人抢到之后还可以再抢,还需要如何改进呢?
作者: 水月灬清影    时间: 2016-8-25 12:42
本帖最后由 水月灬清影 于 2016-8-25 12:54 编辑

感谢 lbx95272006 的指点,把红包资源类的 if 改成 while,notify 改成 notifyAll 可以实现一人一个红包,但是不合题目要求,题目讲的是抢到之后可以再抢,不限次数,所以还需要改进,还有哪位朋友有高见,目前代码如下:

[Java] 纯文本查看 复制代码
import java.util.Random;


//红包资源类
public class Bonus {
        private static int count=5;
        private static int bonus;
        
        private boolean flag;
        
        

        public synchronized void set(){
                while(this.flag==true){
                        try {
                                this.wait();
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                }
                if(count>0){
                        Random r=new Random();
                        bonus=r.nextInt(10)+1;
                        count--;
                        System.out.println("红包已生成");
                        
                        
                }
               
               
                this.flag=true;
                this.notifyAll();
               
        }
        
        public synchronized void get(){
                while(this.flag==false){
                        try {
                                this.wait();
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                }
               
                System.out.println(Thread.currentThread().getName()+bonus+"元");
                try {
                        Thread.sleep(300);
                } catch (InterruptedException e) {
                        e.printStackTrace();
                }
               
                this.flag=false;
                this.notifyAll();
        }
}

作者: 水月灬清影    时间: 2016-8-25 12:57
lbx95272006 发表于 2016-8-25 11:46
问题出在notify() 这个方法,我把你的notify()方法也改了下,改成notifyAll()  前面的方法每次只唤醒一个线 ...

另外我试了一下,只改notifyAll,不把 if 改成 while 也可以实现你的效果。
作者: lbx95272006    时间: 2016-8-25 17:19
题目把你的问题掩盖了,如果题目要求你每次发的红包都要不一样,那么,你的这个程序就会出问题了,因为出现两人同时抢到一样的红包,你可以说是刚好那么巧,两次随机数都一样
把if 改成while    再把 你收红的线程里面的count--放到最后,就可以了
作者: 水月灬清影    时间: 2016-8-25 17:44
lbx95272006 发表于 2016-8-25 17:19
题目把你的问题掩盖了,如果题目要求你每次发的红包都要不一样,那么,你的这个程序就会出问题了,因为出现 ...

照你说的改过之后,抢完5个红包程序不能终止,而且我没明白跟count--在前在后有什么关系
作者: lbx95272006    时间: 2016-8-25 17:49
我也不知道这之间的区别是什么, 所以这是我之前想请教你的,因为我试了下,放前和放后,效果不一样,我也没有想明白是为什么
作者: 水月灬清影    时间: 2016-8-25 18:03
lbx95272006 发表于 2016-8-25 17:49
我也不知道这之间的区别是什么, 所以这是我之前想请教你的,因为我试了下,放前和放后,效果不一样,我也 ...

嗯,等以后对多线程理解深入之后再回过头来看看吧
作者: chensc    时间: 2016-8-26 06:23
学习学习!




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