黑马程序员技术交流社区

标题: java多线程问题 [打印本页]

作者: vipzh    时间: 2013-3-13 22:33
标题: java多线程问题
本帖最后由 张号 于 2013-3-15 12:04 编辑

创建了6个线程,同步后为什么总是只有一个线程在走?
  1. /售票窗口
  2. public class SealWindow
  3. {
  4.         public static void main(String[] args)
  5.         {
  6.                 new Thread(new TicketSealCenter(), "1号窗口").start();
  7.                 new Thread(new TicketSealCenter(), "2号窗口").start();
  8.                 new Thread(new TicketSealCenter(), "3号窗口").start();
  9.                 new Thread(new TicketSealCenter(), "4号窗口").start();
  10.                 new Thread(new TicketSealCenter(), "5号窗口").start();
  11.                 new Thread(new TicketSealCenter(), "6号窗口").start();

  12.         }

  13. }

  14. // 售票中心
  15. class TicketSealCenter implements Runnable
  16. {

  17.         private void sale() throws Exception
  18.         {
  19.                 Ticket ticket = new Ticket();
  20.                 // 售票中心分配火车票
  21.                 ticket.setTicketNum(100);

  22.                 while (ticket.isEmple())
  23.                 {
  24.         
  25.                         System.out.println(Thread.currentThread().getName() + "售出一张"
  26.                                         + "还剩下" + ticket.getTicketNum() + "张票");
  27.                         
  28.                         if (ticket.getTicketNum() == 0)
  29.                         {
  30.                                 System.out.println("票已经卖完了,明天再来吧!!!");
  31.                         }

  32.                 }
  33.         }

  34.         @Override
  35.         public void run()
  36.         {
  37.                 try
  38.                 {
  39.                         synchronized (TicketSealCenter.class)
  40.                         {
  41.                                 
  42.                                 sale();
  43.                         }

  44.                 }
  45.                 catch (Exception e)
  46.                 {
  47.                         e.printStackTrace();
  48.                 }
  49.         }
  50. }

  51. // 火车票类
  52. class Ticket
  53. {

  54.         private int ticketNum; // 火车票张数

  55.         // 获得火车票的数量
  56.         public int getTicketNum()
  57.         {
  58.                 return ticketNum;
  59.         }

  60.         // 设置火车票数量
  61.         public void setTicketNum(int ticketNum)
  62.         {
  63.                 this.ticketNum = ticketNum;
  64.         }

  65.         // 判断是否有票
  66.         public  boolean isEmple() throws Exception
  67.         {

  68.                 if (ticketNum > 0)
  69.                 {

  70.                         ticketNum--;
  71.                         Thread.sleep(1000);
  72.                         return true;
  73.                 }
  74.                 else
  75.                 {
  76.                         System.exit(0);
  77.                         return false;
  78.                 }
  79.         }

  80. }
复制代码

作者: HM赵磊    时间: 2013-3-13 22:46
[ 本帖最后由 csatshell 于 2013-3-13 22:49 编辑 ]\n\n兄弟,你的程序运行后,只有1号窗口买票,原因是你的同步代码块的锁选择的问题 看如下代码(更改你的锁标志)

                                        //售票窗口
public class SealWindow
{
        public static void main(String[] args)
        {
                new Thread(new TicketSealCenter(), "1号窗口").start();
                new Thread(new TicketSealCenter(), "2号窗口").start();
                new Thread(new TicketSealCenter(), "3号窗口").start();
                new Thread(new TicketSealCenter(), "4号窗口").start();
                new Thread(new TicketSealCenter(), "5号窗口").start();
                new Thread(new TicketSealCenter(), "6号窗口").start();        }}// 售票中心
class TicketSealCenter implements Runnable
{        private void sale() throws Exception
        {
                Ticket ticket = new Ticket();
                // 售票中心分配火车票
                ticket.setTicketNum(100);                while (ticket.isEmple())
                {
        
                        System.out.println(Thread.currentThread().getName() + "售出一张"
                                        + "还剩下" + ticket.getTicketNum() + "张票");
                        
                        if (ticket.getTicketNum() == 0)
                        {
                                System.out.println("票已经卖完了,明天再来吧!!!");
                        }                }
        }        //@Override
  Object obj=new Object();//添加的
        public void run()
        {
                try
                {
                        synchronized (obj)
                        {
                                
                                sale();
                        }                }
                catch (Exception e)
                {
                        e.printStackTrace();
                }
        }
}// 火车票类
class Ticket
{        private int ticketNum; // 火车票张数        // 获得火车票的数量
        public int getTicketNum()
        {
                return ticketNum;
        }        // 设置火车票数量
        public void setTicketNum(int ticketNum)
        {
                this.ticketNum = ticketNum;
        }        // 判断是否有票
        public  boolean isEmple() throws Exception
        {                if (ticketNum > 0)
                {                        ticketNum--;
                        Thread.sleep(1);
                        return true;
                }
                else
                {
                        System.exit(0);
                        return false;
                }
        }}
                 

d.jpg (63.36 KB, 下载次数: 25)

d.jpg

作者: 马甲大王    时间: 2013-3-13 22:58
本帖最后由 张栓紧 于 2013-3-13 23:00 编辑
  1. public class SealWindow
  2. {
  3.         public static void main(String[] args)
  4.         {
  5.                 new Thread(new TicketSealCenter(), "1号窗口").start();
  6.                 new Thread(new TicketSealCenter(), "2号窗口").start();
  7.                 new Thread(new TicketSealCenter(), "3号窗口").start();
  8.                 new Thread(new TicketSealCenter(), "4号窗口").start();
  9.                 new Thread(new TicketSealCenter(), "5号窗口").start();
  10.                 new Thread(new TicketSealCenter(), "6号窗口").start();

  11.         }

  12. }

  13. // 售票中心
  14. class TicketSealCenter implements Runnable
  15. {
  16.          
  17.        // 售票中心分配火车票
  18.       

  19.         private void sale() throws Exception
  20.         {
  21.                  Ticket ticket = new Ticket();
  22.                     ticket.setTicketNum(10);

  23.                 while (ticket.isEmple())
  24.                 {
  25.         
  26.                         System.out.println(Thread.currentThread().getName() + "售出一张"
  27.                                         + "还剩下" + ticket.getTicketNum() + "张票");
  28.                         
  29.                         if (ticket.getTicketNum() == 0)
  30.                         {
  31.                                 System.out.println("票已经卖完了,明天再来吧!!!");
  32.                         }

  33.                 }
  34.         }

  35.         @Override
  36.         public void run()
  37.         {
  38.                 try
  39.                 {
  40.                         synchronized (this)
  41.                         {
  42.                                 
  43.                                 sale();
  44.                         }

  45.                 }
  46.                 catch (Exception e)
  47.                 {
  48.                         e.printStackTrace();
  49.                 }
  50.         }
  51. }

  52. // 火车票类
  53. class Ticket
  54. {

  55.         private int ticketNum; // 火车票张数

  56.         // 获得火车票的数量
  57.         public int getTicketNum()
  58.         {
  59.                 return ticketNum;
  60.         }

  61.         // 设置火车票数量
  62.         public void setTicketNum(int ticketNum)
  63.         {
  64.                 this.ticketNum = ticketNum;
  65.         }

  66.         // 判断是否有票
  67.         public  boolean isEmple() throws Exception
  68.         {

  69.                 if (ticketNum > 0)
  70.                 {

  71.                         ticketNum--;
  72.                         Thread.sleep(1000);
  73.                         return true;
  74.                 }
  75.                 else
  76.                 {
  77.                         System.exit(0);
  78.                         return false;
  79.                 }
  80.         }

  81. }
复制代码
你把TicketSealCenter类锁死了,所以就只是一个线程在运行
作者: filter    时间: 2013-3-14 00:44
失眠了,半夜来论坛逛下,我修改了下并测试了下代码,至少是能保证安全问题,肯定是可以优化的,明天有空的话我再来看看,希望别的同学帮着优化下
  1. package com.itheima;

  2. public class Test11
  3. {
  4.         public static void main(String[] args)
  5.         {
  6.                 [color=Red]Ticket1 ticket = new Ticket1(100);//初始化票的数量[/color]               
  7. new Thread(new TicketSealCenter1(ticket), "1号窗口").start();
  8.                 new Thread(new TicketSealCenter1(ticket), "2号窗口").start();
  9.                 new Thread(new TicketSealCenter1(ticket), "3号窗口").start();
  10.                 new Thread(new TicketSealCenter1(ticket), "4号窗口").start();
  11.                 new Thread(new TicketSealCenter1(ticket), "5号窗口").start();
  12.                 new Thread(new TicketSealCenter1(ticket), "6号窗口").start();

  13.         }

  14. }

  15. // 售票中心
  16. class TicketSealCenter1 implements Runnable
  17. {
  18.          
  19.        // 售票中心分配火车票
  20.       
  21.       [color=Red]private Ticket1 ticket;//Ticket对象最好定义在成员位置上[/color]
  22.         //ticket.setTicketNum(100);
  23.         TicketSealCenter1(Ticket1 ticket){
  24.                 this.ticket = ticket;
  25.         }
  26.       
  27.         private void sale() throws Exception
  28.         {
  29.                  //Ticket1 ticket = new Ticket1();
  30.                   // ticket.setTicketNum(100);
  31.                        
  32.                 while (ticket.isEmple())
  33.                 {
  34.                         [color=Red]int count = ticket.getTicketNum();//定义临时变量,记录票的数量[/color]                       
  35.                                         System.out.println(Thread.currentThread().getName()
  36.                                                         + "售出一张" + "还剩下" + count
  37.                                                         + "张票");
  38.                         
  39.                                         if (count == 0) {
  40.                                                 System.out.println("票已经卖完了,明天再来吧!!!");
  41.                                         }
  42.                 }
  43.         }

  44.         @Override
  45.         public void run()
  46.         {
  47.                 try
  48.                 {
  49.                         [color=Red]synchronized (this)//方法的锁最好定义为调用者this[/color]                        {
  50.                                 
  51.                                 sale();
  52.                         }

  53.                 }
  54.                 catch (Exception e)
  55.                 {
  56.                         e.printStackTrace();
  57.                 }
  58.         }
  59. }

  60. // 火车票类
  61. class Ticket1
  62. {

  63.         private int ticketNum = 100; // 火车票张数
  64.         Ticket1(int ticketNum){
  65.                 this.ticketNum = ticketNum;
  66.         }

  67.         // 获得火车票的数量
  68.         [color=Red]public synchronized int getTicketNum()//被多条线程操作的数据,要加同步[/color]        {
  69.                 return --ticketNum;
  70.         }

  71.         // 设置火车票数量
  72.         public void setTicketNum(int ticketNum)
  73.         {
  74.                 this.ticketNum = ticketNum;
  75.         }

  76.         // 判断是否有票
  77.        [color=Red] public synchronized boolean isEmple() throws Exception//被多条线程操作的数据,要加同步[/color]        {

  78.                 if (ticketNum > 0)
  79.                 {

  80.                                
  81.                         Thread.sleep(1000);
  82.                         return true;
  83.                 }
  84.                 else
  85.                 {
  86.                         System.exit(0);
  87.                         return false;
  88.                 }
  89.         }

  90. }
复制代码

作者: filter    时间: 2013-3-14 00:46
我去,论坛还玩儿不转,怎么设置注释的字体啊??{:soso_e127:}
作者: 李辉    时间: 2013-3-14 02:13
本帖最后由 李辉 于 2013-3-14 02:16 编辑

这里的问题不少啊!
第一点:最重要的也是最根本的问题是对多线程共享资源的不理解!除了李志阳,前几位创建的线程完全没有共享资源,每个线程都独立的拥有100张票(有一个人定义了10张),我要在这里说清楚恐怕得写太多。大家自己先好好学学。
第二点:类名。包含主函数的类才应该叫“TicketSealCenter“ 因为是这个类运行的时候创建了多个线程并且在调度这些线程,每个线程代表一个售票窗口。实现Runnable接口的类应该叫“SealWindow”。类名不单单是个单词,它代表着你对售票模型以及面向对象的理解。
第三点:同步的理解。同步是防止一个线程对共享数据操作一半的时候另一个线程开始操作。前几位都没有共享数据,同步只能起到一个作用:就是降低程序运行速度。

作者: 0.00    时间: 2013-3-14 04:57
表示弄了很久还是没弄好,起床再搞了,困死了 都天亮了,
你代码存在很多问题,正如楼上所说,锁只是锁共享的数据,而数据只有票在变,要锁住票, 还有一个就是 多线程不能像你那样传对象,那样的对象是独立的线程了,
需要同时传同一个对象进去!
作者: filter    时间: 2013-3-14 09:58
楼上说的很到位,给你提供了思路,具体问题还是你自己解决吧,另外我多线程学的也不是很好,最后加的锁是嵌套的死锁,只卖几百张票可能还行,多了就出大问题了
,可能跟设计的方法有关吧
晚上再来看下
作者: 0.00    时间: 2013-3-14 19:20
public class SaleWindow
{
       public static void main(String[] args)
     {
                Thread t1=new Thread(new TicketSealCenter("1号窗口"));
                Thread t2=new Thread(new TicketSealCenter("2号窗口"));
                Thread t3=new Thread(new TicketSealCenter("3号窗口"));
                Thread t4=new Thread(new TicketSealCenter("4号窗口"));
                Thread t5=new Thread(new TicketSealCenter("5号窗口"));
                Thread t6=new Thread(new TicketSealCenter("6号窗口"));
                t1.start();t2.start();t3.start();t4.start();t5.start();t6.start();
               
                System.out.println("关门下班");
        }
}
//新建一个类
class  TicketSealCenter implements Runnable
{      
        private String iname;
       
        private static int inumber=100;
       
        Object o=new Object();
       
        public  void run()
    {
                if(inumber>0)
          { while(true)
                        {
                synchronized (o)
            {
                if(inumber>0)
                        {
                         System.out.println(this.getIname()+"火车票卖出一张,"+"剩余"+--inumber+"张.");
                         try
                            {Thread.sleep(1);}
                         catch (Exception e)
                                {System.out.println("系统异常");}
                        } else
                  break;
                        }
                       
                       
            }
         
         }
          
          }       
                       
       
       
        public String getIname()
          {
        return iname;
          }
        TicketSealCenter(String iname)
          {
         this.iname=iname;
          }
       
}
你试试这个代码
作者: 0.00    时间: 2013-3-14 19:23
还是没锁住,坐等大神出现
作者: 0.00    时间: 2013-3-14 20:34
把锁的对象改为 类名.class,否则不是同一个锁




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