问题描述
问题1代码:publicclassMyThreadextendsThread{privatestaticinttickets=100;@Overridepublicvoidrun(){while(tickets>0)System.out.println(getName()+"正在出售第"+(tickets--)+"张票");}}publicclassMYThreadDemo{publicstaticvoidmain(String[]args){MyThreadmy1=newMyThread();MyThreadmy2=newMyThread();my1.setName("窗口1");my2.setName("窗口2");my1.start();my2.start();}}运行结果:窗口2正在出售第100张票窗口1正在出售第100张票窗口1正在出售第99张票窗口2正在出售第98张票窗口1正在出售第97张票窗口2正在出售第96张票窗口1正在出售第95张票后面就省略。问题1:为什么只是偶尔出现这种问题,但有时候运行情况又是正确?问题2代码:publicclassSellTicketimplementsRunnable{//定义100张票privateinttickets=100;@Overridepublicvoidrun(){while(true){if(tickets>0){System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"张票");}}}}publicclassSellTicketDemo{publicstaticvoidmain(String[]args){SellTicketst=newSellTicket();Threadt1=newThread(st,"窗口1");Threadt2=newThread(st,"窗口2");Threadt3=newThread(st,"窗口3");t1.start();t2.start();t3.start();}}运行结果是正确的,问题2:但是不是说CPU操作必须是原子性,它有ticket--却不会出现多个窗口售卖相同票呢?就是线程延时所遇到的问题。求大神解决啊一直想不通就是这两个问题不用讲怎么改进用锁同步实现我会主要讲这两个问题出现的原因就行跪谢!
解决方案
解决方案二:
个人认为单核cpu不会出现不正常的情况,多核cpu会出现不正常情况。原因:1、单核cpu执行多线程实际上是来回切换执行线程(1线程执行了一次,切换到2线程执行,甚至于连续执行某个线程),由于是单核,所以第二次执行的线程必然等到第一次完成后才有机会执行(必然出现时间差)。2、多核cpu,cpu1执行的时候,cpu2同样可以执行,那么这时就可能出现同时操作tickets的情况,就是你打印出来的“窗口2正在出售第100张票”说的不对望指正,个人对cpu如何执行指令没有研究过。
解决方案三:
我觉得,把票数定义在线程里是不对的,这样子不就是各个线程启动后,处理的都是各自的票数吗?改成下面这样,放在主线程里定义,就不会出错。classMyThreadextendsThread{privateintnum;publicMyThread(intnum){this.num=num;}@Overridepublicvoidrun(){while(num>0)System.out.println(getName()+"正在出售第"+(num--)+"张票");}}publicclassTest2{publicstaticvoidmain(String[]args){finalintnum=100;MyThreadmy1=newMyThread(num);MyThreadmy2=newMyThread(num);my1.setName("窗口1");my2.setName("窗口2");my1.start();my2.start();}}
解决方案四:
第一段代码:你只有两个线程,运行哪一个线程是JVM说了算的,两个线程是交替运行的,之所以看起来有的时候没有问题是因为你的线程的数量太少了,如果你的线程多一些,一定会不按照顺序依次执行的现象出现第二段代码:你在每一个SellTicket里面都有100张票,相当于每个窗口都给了100张票,窗口间谁先卖谁后卖会乱,但是每个窗口自己卖票的顺序一定是从100到1递减的,所以没有你认为的混乱的问题第一个回复:你的理解是错误的,JVM相当于是一个虚拟机,JVM里面运行的代码和计算机有几个核是没有关系的
解决方案五:
引用3楼sinat_16569125的回复:
第二段代码:你在每一个SellTicket里面都有100张票,相当于每个窗口都给了100张票,窗口间谁先卖谁后卖会乱,但是每个窗口自己卖票的顺序一定是从100到1递减的,所以没有你认为的混乱的问题
你的理解是错误的,实际上第二段代码是3个窗口共同卖那100张票,每个窗口卖票的顺序并不是100到1递减,有可能中间的会跳过,被别的窗口卖了的
解决方案六:
多线程同时访问同一个全局变量,当然会线程安全的问题了。publicclassTestextendsThread{privatestaticinttickets=100;privateStringname;publicTest(Stringname){this.name=name;}privatestaticsynchronizedintsellOneTicket(){returntickets--;}privatestaticbooleanhaveTicket(){booleanb=false;if(tickets>0){b=true;}returnb;}@Overridepublicvoidrun(){while(Test.haveTicket()){System.out.println(this.name+"正在出售第"+sellOneTicket()+"张票");}}//Main方法publicstaticvoidmain(String[]args){Testt1=newTest("窗口1");Testt2=newTest("窗口2");t1.start();t2.start();}}
运行结果:窗口1正在出售第100张票窗口1正在出售第99张票窗口1正在出售第98张票窗口1正在出售第97张票窗口1正在出售第95张票窗口2正在出售第96张票窗口1正在出售第94张票窗口2正在出售第93张票窗口1正在出售第92张票窗口2正在出售第91张票窗口1正在出售第90张票窗口2正在出售第89张票窗口1正在出售第88张票窗口2正在出售第87张票窗口1正在出售第86张票窗口2正在出售第85张票窗口1正在出售第84张票窗口2正在出售第83张票本人I7处理器4核。
解决方案七:
第一个问题,访问全局变量线程不安全,出现原因是因为,当线程1执行ticket=100时,在没有真正执行后面的打印部分之前,ticket仍然等于100,此时cpu切换到线程2,它看到的ticket也等于100,因此会出现你说的问题,只要锁同步就行第二个问题,就是你自己说的,他们三个在同卖那个ticket,cpu操作肯定是原子性的望给分啊
解决方案八:
一句java的代码对cpu来说不是只执行一步,例如a=b--;对cpu来说就是把b的值取出来——然后给a——把a存进去——把b-1——再把b存进去。没记错应该是分这几步。中间没有锁定之类的是随时都有可能断掉的。
解决方案九:
解决方案十:
用队列,线程安全,初始化长度为100,取出后长度减少,当返回null时,表示票卖完了,如果中间抛异常了还可以把对象加到队列中。privatestaticBlockingQueue<对象>queue=newArrayBlockingQueue<对象>(100);
解决方案十一:
对于第一个问题应该System.out.println操作属于I/O操作,会花费大量的时间,所以导致了你所看到的只是偶尔遇到两个窗口卖相同票的情况,试试将输出先缓存,在线程结束后一次性输出看看。(没做验证请见谅)