黑马程序员技术交流社区

标题: 多线程代码的安全问题【求各位指点一下】 [打印本页]

作者: 何仕映    时间: 2013-3-21 16:18
标题: 多线程代码的安全问题【求各位指点一下】
本帖最后由 何仕映 于 2013-3-21 23:17 编辑

下面这个程序是同步函数和同步代码块的练习,我稍稍改动了一下,我始终不明白0号票,为什么能被打印。在这个代码中,同步的锁我用的是两个不同的锁,就算不是同一个锁,但是在同步代码块中,之中都只有一个线程在执行。并且就算在执行之前几个线程都通过了标志位的判断,释放了执行权。当进入同步代码块中,也有一个if(ticket>0)的判断。如果等于0了,就不会执行if里面的内容了,但是为什么还是可以打出0号票呢?求分
  1. class Ticket implements Runnable
  2. {
  3.         private  int tick = 200;
  4.         boolean flag = true;
  5.         Object obj = new Object();
  6.         public void run()
  7.         {
  8.                 while(tick>0)
  9.                 {
  10.                         if (flag)//如果标志位为真则执行同步函数。
  11.                         {
  12.                                 try{Thread.sleep(40);}catch(Exception e){}
  13.                                 //为了让几个线程在执行前同步函数前,都通过标志位的判断
  14.                                 show();
  15.                         }

  16.                         if(!flag)        //如果标志位为假则执行同步代码块
  17.                         {
  18.                                 try{Thread.sleep(100);}catch(Exception e){}
  19.                                 //为了让几个线程在执行前同步函数前,都通过标志位的判断
  20.                                 synchronized (obj)
  21.                                 {
  22.                                         if(tick>0)
  23.                                         {
  24.                                                 try{Thread.sleep(40);}catch(Exception e){}
  25.                                                 System.out.println(Thread.currentThread().getName()+"....站票 : "+ tick--);
  26.                                                 flag = true;
  27.                                         }
  28.                                 }
  29.                         }
  30.                 }
  31.         }
  32.         public synchronized void show()//同步函数
  33.         {
  34.                 if(tick>0)
  35.                 {try{Thread.sleep(10);}catch(Exception e){}
  36.                         System.out.println(Thread.currentThread().getName()+"坐票 : "+ tick--);
  37.                         flag = false;
  38.                 }
  39.         }
  40. }

  41. class  TicketDemo
  42. {
  43.         public static void main(String[] args)
  44.         {
  45.                 Ticket t = new Ticket();
  46.                 Thread t1 = new Thread(t);//创建了一个线程;
  47.                 Thread t2 = new Thread(t);//创建了一个线程;
  48.                 Thread t3 = new Thread(t);//创建了一个线程;
  49.                 Thread t4 = new Thread(t);//创建了一个线程;
  50.                 t1.start();
  51.                 t2.start();
  52.                 t3.start();
  53.                 t4.start();
  54.         }
  55. }
复制代码
析。


作者: 陈原野    时间: 2013-3-21 16:51
在多线程编程中,这种会被多个线程同时访问的资源叫做临界资源。

Synchronized关键字是一个修饰符,可以修饰方法或代码块。其作用是:对于同一个对象(不是一个类的不同对象),当多个线程都同时调用该方法或代码块时,必须一次执行,也就是说,如果两个或两个以上的线程同时执行该段代码,如果一个线程已经开始执行该段代码,则另外一个线程必须等待这个线程执行完这段代码才能开始执行。
多线程的同步提高了系统的安全问题

线程同步的两种表现形式:
1.同步代码块。

synchronzied(对象锁){
需要被同步的代码。(哪些需要同步哪些不需要一定要分清)
}

2.同步函数。

就是在函数上加了synchronzied关键字进行修饰。、
同步代码块可以使用任意对象作为锁。
同步函数使用的锁只有一个,就是this。
注意:static同步函数使用的锁是该函数所属类的对象。类名.class
作者: 陈原野    时间: 2013-3-21 16:51
在多线程编程中,这种会被多个线程同时访问的资源叫做临界资源。

Synchronized关键字是一个修饰符,可以修饰方法或代码块。其作用是:对于同一个对象(不是一个类的不同对象),当多个线程都同时调用该方法或代码块时,必须一次执行,也就是说,如果两个或两个以上的线程同时执行该段代码,如果一个线程已经开始执行该段代码,则另外一个线程必须等待这个线程执行完这段代码才能开始执行。
多线程的同步提高了系统的安全问题

线程同步的两种表现形式:
1.同步代码块。

synchronzied(对象锁){
需要被同步的代码。(哪些需要同步哪些不需要一定要分清)
}

2.同步函数。

就是在函数上加了synchronzied关键字进行修饰。、
同步代码块可以使用任意对象作为锁。
同步函数使用的锁只有一个,就是this。
注意:static同步函数使用的锁是该函数所属类的对象。类名.class
作者: HM刘博    时间: 2013-3-21 17:16
本帖最后由 HM刘博 于 2013-3-21 17:37 编辑

程序中同步函数和同步代码块用的不是一个锁,,所以造成打印错票,将程序修改一下使同步使用同一个锁
  1. class Ticket implements Runnable
  2. {
  3.       private int tick = 200;
  4.       boolean flag = true;
  5.       Object obj = new Object();
  6.       public void run()
  7.       {
  8.             while(tick>0)
  9.             {
  10.                   if (flag)//如果标志位为真则执行同步函数。
  11.                    {
  12.                            try{Thread.sleep(10);}catch(Exception e){}
  13.                          //为了让几个线程在执行前同步函数前,都通过标志位的判断
  14.                          synchronized (obj)//<FONT color=red>锁为obj
  15. </FONT>                          {
  16.                                  if(tick>0)
  17.                                {try{Thread.sleep(10);}catch(Exception e){}
  18.                                   System.out.println(Thread.currentThread().getName()+"坐票 : "+ tick--);
  19.                                  flag = false;
  20.                                 }
  21.                            }
  22.                      }

  23.                          if(!flag) //如果标志位为假则执行同步代码块
  24.                         {
  25.                               try{Thread.sleep(10);}catch(Exception e){}
  26.                             //为了让几个线程在执行前同步函数前,都通过标志位的判断
  27.                                synchronized (obj)//<FONT color=red>锁为obj
  28. </FONT>                                {
  29.                                         if(tick>0)
  30.                                          {
  31.                                               try{Thread.sleep(10);}catch(Exception e){}
  32.                                               System.out.println(Thread.currentThread().getName()+"....站票 : "+ tick--);
  33.                                              flag = true;
  34.                                          }
  35.                                 }
  36.                        }
  37.                }
  38.       }

  39. }

  40. class TicketDemo
  41. {
  42.       public static void main(String[] args)
  43.       {
  44.           Ticket t = new Ticket();
  45.           Thread t1 = new Thread(t);//创建了一个线程;
  46.           Thread t2 = new Thread(t);//创建了一个线程;
  47.           Thread t3 = new Thread(t);//创建了一个线程;
  48.           Thread t4 = new Thread(t);//创建了一个线程;
  49.           t1.start();
  50.           t2.start();
  51.           t3.start();
  52.            t4.start();
  53.      }
  54. }
复制代码

作者: 何仕映    时间: 2013-3-21 17:31
HM刘博 发表于 2013-3-21 17:16
我的个人理解
在程序运行过程中,也可能遇到这种情况:
因为程序中判断符合条件后等待的时间不同,会造成打 ...

你的意思是t1在判断标志位后t2获取了执行权,即t1和t2都在程序的第19行,但是进入同步代码块中的线程每次都只有一个啊。不管是t1还是t2进去,那么最后一张票打印完后,tick的值就变成0了。当此线程执行完出同步代码块,另一线程进来后,判断if(tick>0)为假,则不会执行里面的语句了,自然也就不会打印出0号票了啊。
作者: HM刘博    时间: 2013-3-21 17:38
何仕映 发表于 2013-3-21 17:31
你的意思是t1在判断标志位后t2获取了执行权,即t1和t2都在程序的第19行,但是进入同步代码块中的线程每次 ...

这个错了,不好意思,是同步不是同一个锁的问题吧
作者: 陈圳    时间: 2013-3-21 17:57
我要中奖!!!
作者: 何仕映    时间: 2013-3-21 18:23
陈圳 发表于 2013-3-21 17:57
我要中奖!!!

给点儿指点撒




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