A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 杨希 中级黑马   /  2014-4-8 14:58  /  1361 人查看  /  8 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 杨希 于 2014-4-8 16:26 编辑

跟毕姥爷学习多线程这块的时候,写了一些代码,现在复习的时候有一块有点不明白,求解
  1. /*
  2. 多线程卖票程序
  3. */

  4. class Ticket implements Runnable
  5. {
  6.         private int tick = 100;
  7.         Object obj = new Object();  //这块为什么要创建Object对象
  8.         public void run()
  9.         {
  10.                 while(true)
  11.                 {
  12.                         synchronized(obj)   //有这个锁的原因
  13.                         {
  14.                                 if(tick>0)        
  15.                                 System.out.println(Thread.currentThread().getName()+"..sale:"+tick--);
  16.                
  17.                         }
  18.                 }
  19.         }
  20. }

  21. class ThreadText2
  22. {
  23.         public static void main(String[] args)
  24.         {
  25.                 Ticket t =  new Ticket();
  26.                 Thread t1 = new Thread(t);
  27.                 Thread t2 = new Thread(t);
  28.                 Thread t3 = new Thread(t);
  29.                 Thread t4 = new Thread(t);
  30.                  
  31.                 t1.start();
  32.                 t2.start();
  33.                 t3.start();
  34.                 t4.start();
  35.         }
  36. }
复制代码

我自己又写了一个,发现能运行,求大家给看看跟上面这个比,有啥弊端
  1. class Demo3
  2. {
  3.         public static void main(String args[])
  4.         {
  5.                 Ticket t =new Ticket();
  6.                 Thread t1 =new Thread(t);
  7.                 Thread t2 =new Thread(t);
  8.                 Thread t3=new Thread(t);
  9.                 t1.start();
  10.                 t2.start();
  11.                 t3.start();
  12.                         
  13.         }
  14. }
  15. class Ticket implements Runnable
  16. {
  17.         private int x =20;
  18.         
  19.         public void run()
  20.         {
  21.                 for(int y=0;y<=x;y++)
  22.                 {
  23.                                 System.out.println(Thread.currentThread().getName()+"sale"+x);
  24.                                 x--;
  25.                 }
  26.         }
复制代码


后来我根据毕姥爷的代码编译了一下,发现我输出的结果都是Thread-0,应该是有3个线程同时进行,我记得毕姥爷说过这个问题,但是我给忘了,大家还记得吗?
Thread-0sale20
Thread-0sale19
Thread-0sale18
Thread-0sale17
Thread-0sale16
Thread-0sale15
Thread-0sale14
Thread-0sale13
Thread-0sale12
Thread-0sale11
Thread-0sale10
Thread-0sale9
Thread-0sale8
Thread-0sale7
Thread-0sale6
Thread-0sale5
Thread-0sale4
Thread-0sale3
Thread-0sale2
Thread-0sale1

评分

参与人数 1技术分 +1 收起 理由
itpower + 1

查看全部评分

8 个回复

倒序浏览
还是得加锁。因为得让for循环具备原子性。

for(int y=0; y<=x; y++)
{
          System.out.println(Thread.currentThread().getName()+"sale"+x);   ①
          x--;   ②
}

应该给语句1和2加锁。如果执行到①,线程1被阻塞了。这时候线程2又进来,判断x跟线程1的判断结果一样,线程2执行完毕,假设此时线程3又开始执行for循环,执行结束后,线程2接着执行,总是没有执行到线程1,那么当线程2和线程3将x减为0时,这时候线程1得到了执行权,这时候,在执行下面的语句会发生异常的 。

评分

参与人数 1技术分 +1 收起 理由
itpower + 1

查看全部评分

回复 使用道具 举报
synchronized 块

ynchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法,有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,直接运行。

通过 synchronized关键字来声明synchronized 块。语法如下:
synchronized(syncObject) {
//允许访问控制的代码
}
synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject (可以是类实例或类)的锁方能执行。
在多线程程序的其他部分可能会发生与这个synchronized 代码块同步的代码,这个时候加synchronized() 锁中的对象可以使同一个对象,就可以解决同步带来的问题

你的代码没有synchronized 锁,所以在运行的时候会发生同步的问题,即多个线程同时执行,在不同的情况下会获得不同的结果。加上synchronized 锁后可以安全。

评分

参与人数 1技术分 +1 收起 理由
itpower + 1

查看全部评分

回复 使用道具 举报
当多线程操作同一个成员变量时,为了安全,需要用static 修饰成员变量,或者在操作这个变量的代码区加上线程安全代码块。否则会出现重复的票值,也有可能出现负数。

评分

参与人数 1技术分 +1 收起 理由
ily521125 + 1

查看全部评分

回复 使用道具 举报
你定义的数太小了其它线程来不及抢到执行权就结束了
定义100  或1000就能看到多线程了 也能看到安全问题了
而且多线程每次运行结果都 不一样的 多运行几遍。

评分

参与人数 1技术分 +1 收起 理由
ily521125 + 1

查看全部评分

回复 使用道具 举报
不加synchronized的话,会出现线程安全问题,你可以将总票数的值设定多一些,然后逐个观察,可以发现在不加锁的情况下,会出现打印的票序混乱

评分

参与人数 1技术分 +1 收起 理由
ily521125 + 1

查看全部评分

回复 使用道具 举报
要创建Object对象是为了让synchronized,这是因为synchronized后面需要跟类,所以定义超类来满足语法要求,加锁是为了防止会出现重复的票值,以及负数!!

评分

参与人数 1技术分 +1 收起 理由
ily521125 + 1

查看全部评分

回复 使用道具 举报
[b
]第一个问题:为什么都是Thread-0:
因为cpu处理速度太快了,别的线程没有机会进来,它就结束了!您可以试试让它运行一会
第二个问题:就是那个同步代码块?
当多条线程操作同一个共享数据时,就会出现线程安全问题,
还有那个锁,就是用来监视你同步代码块中的线程,如果里面有线程,就不让它进,没有就,就让它进

评分

参与人数 1技术分 +1 收起 理由
ily521125 + 1

查看全部评分

回复 使用道具 举报
关于为什么创建Object对象,是因为synchronized后面必须要跟个锁对象,这个锁可以是任意对象,所以创建了这个Object超类的对象。不用这个对象也行,你可以任意创建个对象,比如说代码中Tick类的对象也行。
synchronized如果写在方法上,虽然后面不写锁对象,但是自带的有个默认锁对象,非静态方法锁对象是this,静态方法锁对象是所在类的.class字节码对象。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马