黑马程序员技术交流社区

标题: 多线程中,我如何计数,求高手帮我看看我写的代码 [打印本页]

作者: 黑马肖凯骏    时间: 2012-3-17 20:18
标题: 多线程中,我如何计数,求高手帮我看看我写的代码
  1. /**
  2. * @author xiaokaijun
  3. * 设计一个生产电脑和搬运电脑的类,要求生产出一台电脑就搬走一台电脑,
  4. * 如果没有新的电脑生产出来,则搬运工要等待新电脑产出,如果生产电脑没有搬走,
  5. * 则要等待电脑搬走之后再生产,并统计出生产的电脑数量
  6. *思路:生产者消费者模式
  7. *定义个三个类:商品,消费者,生产者
  8. *商品类:
  9.         *产品名称
  10.         *同步方法
  11.          *标志位 为false 则生产,不取走,
  12.          *标志位为true 则取走 不生产
  13.          *生产完或者取走之后,唤醒下一个线程
  14. *消费者和消费者实现Runnable接口
  15. *消费者:
  16. */
  17. class info
  18. {
  19.         private String name="电脑xxx";
  20.         private boolean flag=false;
  21.        
  22.         public synchronized void set(String name)
  23.         {
  24.                 if(!flag)      //标志位为false 则不可以生产
  25.                 {
  26.                         try
  27.                         {
  28.                                 super.wait();
  29.                         }
  30.                         catch(InterruptedException e)
  31.                         {
  32.                                 e.printStackTrace();
  33.                         }
  34.                 }
  35.                 this.name=name;
  36.                 try
  37.                 {
  38.                         Thread.sleep(300);//加入延时
  39.                 }
  40.                 catch(InterruptedException e)
  41.                 {
  42.                         e.printStackTrace();
  43.                 }
  44.                 flag=false;
  45.                 super.notify();
  46.         }
  47.         public synchronized void get()
  48.         {
  49.                 if(flag)//如果为true则不取走,等待生产者生产
  50.                 {
  51.                         try
  52.                         {
  53.                                 super.wait();
  54.                         }
  55.                         catch(InterruptedException e)
  56.                         {
  57.                                 e.printStackTrace();
  58.                         }
  59.                 }
  60.                 try
  61.                 {
  62.                         Thread.sleep(300);
  63.                 }
  64.                 catch(InterruptedException e)
  65.                 {
  66.                         e.printStackTrace();
  67.                 }
  68.                
  69.                 System.out.println(this.getName());
  70.                 flag=true; //取走之后设置标志位为真,表示等待生产者生产
  71.                 super.notify();
  72.         }
  73.         public String getName()
  74.         {
  75.                 return name;
  76.         }
  77.        
  78. }
  79. class Producter implements Runnable
  80. {
  81.         private info info=null;
  82.         public static int count=0;//定义计数器
  83.         public Producter(info info)
  84.         {
  85.                 this.info=info;
  86.         }
  87.         public void run()
  88.         {
  89.                 boolean flag=false;//判断生产电脑A还是电脑B ,间隔生产
  90.                 for(int i=0;i<50;i++)
  91.                 {
  92.                         if(flag) //如果是true则 生产
  93.                         {
  94.                                 this.info.set("电脑B");
  95.                                
  96.                                 flag=false;
  97.                         }
  98.                         else
  99.                         {
  100.                                 this.info.set("电脑A");
  101.                                 flag=true;
  102.                         }
  103.                         count++;//计数
  104.                 }
  105.         }
  106. }
  107. class custorm implements Runnable
  108. {
  109.         private info info=null;
  110.         custorm(info info)
  111.         {
  112.                 this.info=info;
  113.         }
  114.         public void run()
  115.         {
  116.                 for(int i=0;i<50;i++)
  117.                 {
  118.                         try
  119.                         {
  120.                                 Thread.sleep(300); //加入延时
  121.                         }
  122.                         catch(InterruptedException e)
  123.                         {
  124.                                 e.printStackTrace();
  125.                         }
  126.                         this.info.get();
  127.                 }
  128.         }
  129.        
  130. }
  131. public class PBDemo {
  132.         public static void main(String[] args)throws Exception
  133.         {
  134.                 info i=new info();
  135.                 Producter pro=new Producter(i);
  136.                 custorm cus=new custorm(i);
  137.                 new Thread(pro).start();
  138.                 new Thread(cus).start();
  139.                 System.out.println(Producter.count);
  140.         }

  141. }
复制代码
我想统计总共生产了多少台电脑。请问该怎么修改代码?多线程之间切换,我怎么样才能精确的让我统计数字的那句话,是在最后拿到的呢?

最终拿到count的正确值
作者: 于紫洋    时间: 2012-3-17 20:40
我第一反应是定义一个初值0的 int 变量然后再生产者里自增,那个值不就是生产的台数么
同为新手,想法而已,请高手补充
作者: 黑马肖凯骏    时间: 2012-3-17 20:44
于紫洋 发表于 2012-3-17 20:40
我第一反应是定义一个初值0的 int 变量然后再生产者里自增,那个值不就是生产的台数么
同为新手,想法而已 ...

  不行啊!我尝试了,在生产者中自增,线程执行的不确定性

代码块之类的我都想过了,还是不知道怎么解决这个问题!

作者: 于紫洋    时间: 2012-3-17 20:47
本帖最后由 于紫洋 于 2012-3-17 20:48 编辑

哦喽,
我看错, 我再看看
作者: 于紫洋    时间: 2012-3-17 20:52
count++; 是不是应该放在set()里
作者: 于紫洋    时间: 2012-3-17 20:57
我觉得95行和101行都放
count++会不会是可行的
作者: 王亚男    时间: 2012-3-17 21:22
黑马肖凯骏 发表于 2012-3-17 20:44
不行啊!我尝试了,在生产者中自增,线程执行的不确定性

代码块之类的我都想过了,还是不知道怎么解决 ...
  1. public void run()
  2.         {
  3.                                 int count=0;
  4.                 boolean flag=false;//判断生产电脑A还是电脑B ,间隔生产
  5.                 for(int i=0;i<50;i++)
  6.                 {
  7.                         if(flag) //如果是true则 生产
  8.                         {
  9.                                info.set("电脑B");
  10.                                 
  11.                                 flag=false;
  12.                         }
  13.                         else
  14.                         {
  15.                                info.set("电脑A");
  16.                                 flag=true;
  17.                         }
  18.                        count++;//计数
  19.                 }
  20.                                 System.out.println(count);
  21.                                
  22.         }
复制代码
count = 50;

话说本例中……你循环多少次不就生产了多少电脑么~
作者: 黑马肖凯骏    时间: 2012-3-17 21:27
王亚男 发表于 2012-3-17 21:22
count = 50;

话说本例中……你循环多少次不就生产了多少电脑么~

那么假如我要分别统计电脑A和电脑B该怎么统计呢?

我等程序运行到一半的时候,我想让它终端,怎么取出正确的统计数目

线程不是一直在跳么?
我的不出来结果呀!
作者: 于紫洋    时间: 2012-3-17 21:43
分别统计就要定义俩了呗,一个set()下放一个
作者: 黄秋    时间: 2012-3-17 22:10
找个线程安全的数据类型,如StringBuffer,每次append("a"),length()就是数量。
作者: 魏群    时间: 2012-3-17 22:32
在factory里创建个count 生产线程没生产一个 count就加1;
main线程里调用子线程的join()方法
                Producter pro=new Producter(i);
                custorm cus=new custorm(i);
                Thread proThread  = new Thread(pro);
                Thread cusThread  = new Thread(cus);
                 proThread.start();
                 cusThread.start();
                 proThread.join();
                 cusThread.join();     
                  //最后输出factory里的count
                 System.out.println(工厂.count);
作者: 周建    时间: 2012-3-17 23:26
class info

{

        private String name=null;

        private boolean flag=false;

        private int temp=0;//标记位,有新电脑为1,无新电脑为0

        public synchronized void set(String name)

        {

                if(!flag)      //标志位为false 则不可以生产

                {

                        try

                        {

                                super.wait();

                        }

                        catch(InterruptedException e)

                        {

                                e.printStackTrace();

                        }

                }
                //判断标记位
                if(temp==0){
                     this.name=name;
                     temp=1;
                }
                try

                {

                        Thread.sleep(300);//加入延时

                }

                catch(InterruptedException e)

                {

                        e.printStackTrace();

                }

                flag=false;

                super.notify();

        }

        public synchronized void get()

        {

                if(flag)//如果为true则不取走,等待生产者生产

                {

                        try

                        {

                                super.wait();

                        }

                        catch(InterruptedException e)

                        {

                                e.printStackTrace();

                        }

                }

                try

                {

                        Thread.sleep(300);

                }

                catch(InterruptedException e)

                {

                        e.printStackTrace();

                }

                //判断标记位
                if(temp!=0){
                    System.out.println(this.getName());
                    temp=0;
                }           

                flag=true; //取走之后设置标志位为真,表示等待生产者生产

                super.notify();

        }

        public String getName()

        {

                return name;

        }

        

}

class Producter implements Runnable

{

        private info info=null;

        public static int count=1;//定义计数器

        public Producter(info info)

        {

                this.info=info;

        }

        public void run()

        {

                boolean flag=false;//判断生产电脑A还是电脑B ,间隔生产

                for(int i=0;i<50;i++)

                {

                        if(flag) //如果是true则 生产

                        {

                                this.info.set("电脑B");

                                

                                flag=false;

                        }

                        else

                        {

                                this.info.set("电脑A");

                                flag=true;

                        }

                        count++;//计数

                }

        }

}

class custorm implements Runnable

{

        private info info=null;

        custorm(info info)

        {

                this.info=info;

        }

        public void run()

        {

                for(int i=0;i<50;i++)

                {

                        try

                        {

                                Thread.sleep(300); //加入延时

                        }

                        catch(InterruptedException e)

                        {

                                e.printStackTrace();

                        }

                        this.info.get();

                }
                System.out.println(Producter.count);//取出最后一台电脑后,统计生产数量
        }

        

}

public class PBDemo {

        public static void main(String[] args)throws Exception

        {

                info i=new info();

                Producter pro=new Producter(i);

                custorm cus=new custorm(i);

                new Thread(pro).start();

                new Thread(cus).start();

               

        }



}

System.out.println(Producter.count);写在主函数里面,主函数运行完就统计结果,而此时子线程还未运行完,此时的count是错误的,我在程序中加入一个标记位temp判断何时生产,何时搬出,在custorm的run()最后一句加上System.out.println(Producter.count);此时可统计出正确结果

作者: 黑马肖凯骏    时间: 2012-3-17 23:36
魏群 发表于 2012-3-17 22:32
在factory里创建个count 生产线程没生产一个 count就加1;
main线程里调用子线程的join()方法
             ...

明白了,谢谢
作者: 李爱军    时间: 2012-3-17 23:49
class info
{
        private String name="电脑xxx";
        private boolean flag=false;
        public static int count=0;//定义计数
        
        public synchronized void set(String name)
        {
                if(!flag)      //标志位为false 则不可以生产
                {
                        try
                        {
                                super.wait();
                        }
                        catch(InterruptedException e)
                        {
                                e.printStackTrace();
                        }
                }
                this.name=name;
                try
                {
                        Thread.sleep(300);//加入延时
                }
                catch(InterruptedException e)
                {
                        e.printStackTrace();
                }
                flag=false;
                count++;//计数加一;
                super.notify();
        }
        public synchronized void get()
        {
                if(flag)//如果为true则不取走,等待生产者生产
                {
                        try
                        {
                                super.wait();
                        }
                        catch(InterruptedException e)
                        {
                                e.printStackTrace();
                        }
                }
                try
                {
                        Thread.sleep(300);
                }
                catch(InterruptedException e)
                {
                        e.printStackTrace();
                }
               
                System.out.println(this.getName());
                flag=true; //取走之后设置标志位为真,表示等待生产者生产
                super.notify();
        }
        public String getName()
        {
                return name;
        }
        
}
class Producter implements Runnable
{
        private info info=null;
        //public static int count=0;//定义计数器
        public Producter(info info)
        {
                this.info=info;
        }
        public void run()
        {
                boolean flag=false;//判断生产电脑A还是电脑B ,间隔生产
                for(int i=0;i<50;i++)
                {
                        if(flag) //如果是true则 生产
                        {
                                this.info.set("电脑B");
                                System.out.println(info.count);//打印计数器的值
                                flag=false;
                        }
                        else
                        {
                                this.info.set("电脑A");
                                flag=true;
                                System.out.println(info.count);//打印计数器的值
                        }
                       // count++;//计数
                }
        }
}
class custorm implements Runnable
{
        private info info=null;
        custorm(info info)
        {
                this.info=info;
        }
        public void run()
        {
                for(int i=0;i<50;i++)
                {
                        try
                        {
                                Thread.sleep(300); //加入延时
                        }
                        catch(InterruptedException e)
                        {
                                e.printStackTrace();
                        }
                        this.info.get();
                }
        }
        
}
public class PBDemo {
        public static void main(String[] args)throws Exception
        {
                info i=new info();
                Producter pro=new Producter(i);
                custorm cus=new custorm(i);
                new Thread(pro).start();
                new Thread(cus).start();
               // System.out.println(info.count);
        }

}
//计数器的定义在info中,他要被所有的生产线程公用。他才会准确计数。
作者: 彭盼    时间: 2012-3-18 00:40
本帖最后由 彭盼 于 2012-3-18 00:46 编辑

可以试试把count定义到info类中:
我修改了下,你看看是不是你想要的结果:


class info
{
        private String name=null;
                 int count=0;
        private boolean flag=true;
       
        public synchronized void set(String name)
        {
                if(!flag)      //标志位为false 则不可以生产
                {
                        try
                        {
                                super.wait();
                        }
                        catch(InterruptedException e)
                        {
                                e.printStackTrace();
                        }
                }
                this.name=name;
                try
                {
                        Thread.sleep(300);//加入延时
                }
                catch(InterruptedException e)
                {
                        e.printStackTrace();
                }
                                System.out.println(Thread.currentThread().getName()+"生产电脑编号为"+this.getName()+this.count);
                flag=false;
                super.notify();
        }
        public synchronized void get()
        {
                if(flag)//如果为true则不取走,等待生产者生产
                {
                        try
                        {
                                super.wait();
                        }
                        catch(InterruptedException e)
                        {
                                e.printStackTrace();
                        }
                }



                try
                {
                        Thread.sleep(300);
                }
                catch(InterruptedException e)
                {
                        e.printStackTrace();
                }
               
                System.out.println(Thread.currentThread().getName()+"搬走电脑编号为"+this.getName()+this.count);
                flag=true; //取走之后设置标志位为真,表示等待生产者生产
                super.notify();
        }
        public String getName()
        {
                return name;
        }
        
}
class Producter implements Runnable
{
        private info info1=null;
        public Producter(info info1)
        {
                this.info1=info1;
        }
        public void run()
        {
                boolean flag=true;//判断生产电脑A还是电脑B ,间隔生产
                               
                for(int i=0;i<50;i++)
                {
                        if(flag) //如果是true则 生产
                        {
                                info1.set("电脑B");
                                
                                flag=false;
                        }
                        else
                        {
                                info1.set("电脑A");
                                flag=true;
                        }
                     
                                }
                       
        }
}
class custorm implements Runnable
{
        private info info1=null;
        custorm(info info1)
        {
                this.info1=info1;
        }
        public void run()
        {               
                                int num=0;
                for(int i=0;i<50;i++)
                {
                        try
                        {
                                Thread.sleep(300); //加入延时
                        }
                        catch(InterruptedException e)
                        {
                                e.printStackTrace();
                        }
                        info1.get();
                num++;//计数
                info1.count=num;
                                }
                                 System.out.println("总共生产电脑数量为:"+info1.count);
        }
        
}
class PBDemo
        {
        public static void main(String[] args)throws Exception
        {
                info i=new info();
                Producter pro=new Producter(i);
                custorm cus=new custorm(i);
                new Thread(pro).start();
                new Thread(cus).start();
                System.out.println(i.count);
        }

}
最后程序运行结果:
[attach]1122[/attach]

未命名.JPG (67.07 KB, 下载次数: 62)

未命名.JPG

作者: 黑马肖凯骏    时间: 2012-3-18 09:18
本帖最后由 黑马肖凯骏 于 2012-3-18 09:41 编辑
彭盼 发表于 2012-3-18 00:40
可以试试把count定义到info类中:
我修改了下,你看看是不是你想要的结果:


非常感谢,这正是我想要的结果!!

太谢谢你了,多线程中我一直没有弄清楚计数怎么计,现在知道怎么放了!

我理解了,你的做法是,讲计数放到线程中,这样计数就不会在不同的线程中切换了,最后只要取出这个count即可!




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