黑马程序员技术交流社区

标题: 重赏,关于线程的这个现象怎么回事,求正确解答 [打印本页]

作者: boboyuwu    时间: 2015-8-31 16:48
标题: 重赏,关于线程的这个现象怎么回事,求正确解答
package ticketDemo;


class ticket implements Runnable{
        private int count=100;
        public void run(){
                while(count>0){
                 
                        System.out.println(Thread.currentThread().getName()+"卖出票"+count--);
                        
                }
        
        }
        
}
public class ticketDemo {

        public static void main(String[] args){
               
                   ticket t=new ticket();
                  Thread thread1=new Thread(t,"线程1");
                  Thread thread2=new Thread(t,"线程2");
                  thread1.start();
                  thread2.start();
        }
      }

输出的一次结果:线程1卖出票100
线程1卖出票99
线程1卖出票98
线程1卖出票97
线程1卖出票96
线程2卖出票100
线程2卖出票94
线程2卖出票93
线程2卖出票92
线程2卖出票91
线程2卖出票90
线程2卖出票89
线程2卖出票88
线程2卖出票87
线程2卖出票86
线程2卖出票85
线程2卖出票84
线程2卖出票83
线程2卖出票82
线程2卖出票81
线程2卖出票80
线程2卖出票79
线程2卖出票78
线程2卖出票77
线程2卖出票76
线程2卖出票75
线程2卖出票74
线程2卖出票73
线程2卖出票72
线程2卖出票71
线程2卖出票70

出现2次售出100  我在想就算一个线程在system 那卡主了  ,当第二个线程执行一次count--输出100的时候那么就算第一个线程被唤醒count也会变成99不是,为什么会输出二个100呢?


作者: liuch111    时间: 2015-8-31 16:48
本帖最后由 liuch111 于 2015-8-31 20:37 编辑

eclipse 设置成单核试一下


作者: dddlinux    时间: 2015-8-31 17:02
Thread thread1=new Thread(t,"线程1");  Thread thread2=new Thread(t,"线程2");
作者: dddlinux    时间: 2015-8-31 17:12
dddlinux 发表于 2015-8-31 17:02
Thread thread1=new Thread(t,"线程1");  Thread thread2=new Thread(t,"线程2");

没写完,点错了,就发出去了,,这不能输出2个100吧, 因为你创建一个封装任务的对象啊,ticket t=new ticket();后面2个线程对象用的都是这任务对象t,你这段代码会输出0,-1非法票数,

还有一种情况是,继承Thead类,如果不把成员变量设为static的,会出现2个100的票,因为创建2个线程对象
封装了2个成员变量count 值为100
作者: boboyuwu    时间: 2015-8-31 17:45
注意这个现象图

111111111111111111111111111111111111.png (10.01 KB, 下载次数: 112)

111111111111111111111111111111111111.png

作者: boboyuwu    时间: 2015-8-31 17:47
dddlinux 发表于 2015-8-31 17:12
没写完,点错了,就发出去了,,这不能输出2个100吧, 因为你创建一个封装任务的对象啊,ticket t=new ti ...

看下面的现象图  这又不是我凭空捏造的  我运行的时候出现了这个现象,还以别说老毕视频中的现象那个太简单,不简单的要自己发现解决
作者: liuch111    时间: 2015-8-31 17:56
本帖最后由 liuch111 于 2015-8-31 20:29 编辑

                        
作者: dddlinux    时间: 2015-8-31 18:09
  1. class ticket implements Runnable {
  2.         private int count = 100;

  3.         public void run() {
  4.                 while (count > 0) {
  5.                        
  6.                         System.out.println(Thread.currentThread().getName() + "卖出票"
  7.                                         + count);
  8.                         try {
  9.                                 Thread.sleep(50);
  10.                         } catch (InterruptedException e) {
  11.                                 // TODO Auto-generated catch block
  12.                                 e.printStackTrace();
  13.                         }
  14.                         count--;
  15.                 }

  16.         }

  17. }

  18. public class ticketDemo {

  19.         public static void main(String[] args) {

  20.                 ticket t = new ticket();
  21.                 Thread thread1 = new Thread(t, "线程1");
  22.                 Thread thread2 = new Thread(t, "线程2");
  23.                 thread1.start();
  24.                 thread2.start();
  25.         }
  26. }
复制代码


我上面回答有问题,实现Runnable接口,也有线程安全问题,因为都是操作都是t,这个对象,
作者: boboyuwu    时间: 2015-8-31 18:43
liuch111 发表于 2015-8-31 17:56
很正常····  
        第五行本来因该是 96,但是你没有用同步   所以两个相互独立的线程同时执行syste ...

我想起来了  我的cpu不是单核    双核的是不是能同一时间能执行2个线程 不像单核同一时刻只能有一个线程执行
作者: boboyuwu    时间: 2015-8-31 20:00
liuch111 发表于 2015-8-31 17:56
很正常····  
        第五行本来因该是 96,但是你没有用同步   所以两个相互独立的线程同时执行syste ...

我又纳闷了   为什么运行了100次都是卖出2张100的票  如果2个线程同时打印应该会出现很多相同的票啊
作者: freehello    时间: 2015-8-31 21:02
本帖最后由 freehello 于 2015-8-31 21:06 编辑

首先线程2拿到执行权,执行到了输出语句,由于count--,所以是先输出,再--,结果输出后,线程1得到了执行权,线程2歇菜了,此时--还未执行。线程1执行到了97,之后count--执行了,因此count=96,此时线程1歇菜了,线程2开始执行,接着上次执行--操作,此时count=95,之后就输出了,因此,缺了个96.

可以用同步锁synchronized解决
作者: 人傻嘴笨脑残    时间: 2015-8-31 21:03
线程同步,加锁,,详细不说了,我懒
作者: freehello    时间: 2015-8-31 21:03
  1.   class ticket implements Runnable{
  2.         private int count=100;
  3.         synchronized public void run(){
  4.                 while(count>0){
  5.                  
  6.                         System.out.println(Thread.currentThread().getName()+"卖出票"+count--);
  7.                         
  8.                 }
  9.         
  10.         }
  11.         
  12. }
复制代码

作者: freehello    时间: 2015-8-31 21:10
对,正解
作者: boboyuwu    时间: 2015-8-31 21:42
liuch111 发表于 2015-8-31 20:16
eclipse 设置成单核试一下

无法设置单核
作者: boboyuwu    时间: 2015-8-31 21:51
liuch111 发表于 2015-8-31 20:16
eclipse 设置成单核试一下

经测试是处理器的问题             单核就没有这个情况   看来原因应该是同时执行了一次100 --   但是我不明白为什么只是同时卖出了100票       从99到1都正常没有同时出现过2张
作者: liuch111    时间: 2015-8-31 22:08
同步可以解决问题··

但是产生你说的这种情况的具体原因是什么 ,我也想知道(我这边运行你的代码很少出现你这种现象)
作者: freehello    时间: 2015-9-1 06:51
本帖最后由 freehello 于 2015-9-1 07:08 编辑

原因请看11楼
作者: boboyuwu    时间: 2015-9-1 08:17
freehello 发表于 2015-8-31 21:02
首先线程2拿到执行权,执行到了输出语句,由于count--,所以是先输出,再--,结果输出后,线程1得到了执行 ...

大哥我问题的重点是为什么线程2也卖出了票100
作者: freehello    时间: 2015-9-1 13:03
不好意思,我是按我的输出分析的,抱歉。
为什么是线程2是100,因为System.out.println是一个函数,它挂起时,将参数count=100,保存到了它的栈中,因此返回时,它接着上次执行,所以是100
兄弟可以拿币吗
作者: 董兴朋    时间: 2015-9-1 16:00
“卖票”这个问题需要同步线程,同步线程可以使线程1和线程2共享资源,你可以使用synchronized关键字进行同步,或者使用Lock类,来进行同步。
作者: backin    时间: 2015-9-1 19:56
其实这个就是因为运算符优先级的问题。+count--的时候因为打印的优先级比运算的优先级要高,所以是先打印,后运算,在打印过程中线程2进入,导致count的值重复,要解决也很简单将count--的优先级提升用括号括起来先运算在打印重复的现象就不容易出现了。我基本没出现过重复的。。
  1. class ticket implements Runnable {
  2.         private int count = 100;

  3.         public void run() {
  4.                 while (count > 0) {
  5.                         
  6.                         System.out.println(Thread.currentThread().getName() + "卖出票"
  7.                                         + (count--));
  8.                         try {
  9.                                 Thread.sleep(50);
  10.                         } catch (InterruptedException e) {
  11.                                 // TODO Auto-generated catch block
  12.                                 e.printStackTrace();
  13.                         }
  14. //                        count--;
  15.                 }

  16.         }

  17. }

  18. public class ticketDemo {

  19.         public static void main(String[] args) {

  20.                 ticket t = new ticket();
  21.                 Thread thread1 = new Thread(t, "线程1");
  22.                 Thread thread2 = new Thread(t, "线程2");
  23.                 thread1.start();
  24.                 thread2.start();
  25.         }
  26. }
复制代码

作者: boboyuwu    时间: 2015-9-1 21:48
freehello 发表于 2015-9-1 13:03
不好意思,我是按我的输出分析的,抱歉。
为什么是线程2是100,因为System.out.println是一个函数,它挂起 ...

那为什么只有100票打印二次   剩下的99张如果  有一个线程挂起,保存栈中,返回时接着执行应该有很多打印2次的情况为什么我测试几百次都是只打印2次100  其他都正常的
作者: boboyuwu    时间: 2015-9-1 21:53
backin 发表于 2015-9-1 19:56
其实这个就是因为运算符优先级的问题。+count--的时候因为打印的优先级比运算的优先级要高,所以是先打印, ...

括起来问题照样出线
作者: backin    时间: 2015-9-2 10:49
boboyuwu 发表于 2015-9-1 21:53
括起来问题照样出线

你什么电脑{:2_44:}
作者: Doug    时间: 2015-9-3 16:39
ls也能最佳答案。。。醉了。明明是没加锁。




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