刚学线程遇到了两个问题,一直想不通

问题描述

问题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操作,会花费大量的时间,所以导致了你所看到的只是偶尔遇到两个窗口卖相同票的情况,试试将输出先缓存,在线程结束后一次性输出看看。(没做验证请见谅)

时间: 2024-10-03 20:45:12

刚学线程遇到了两个问题,一直想不通的相关文章

17岁...学Java,刚学完框架。,以后的路怎么走,求大神指点

问题描述 刚在培训机构学完Java课程,,就要就业了,,但是觉得很迷茫.不知道以后的路怎么走.学历...高中...瞬间就变成学历==压力了..想搞安卓,但是这刚毕业,继续java的路?学安卓可行吗?会影响以后的路吗?唉16岁的时候看同学搞了一个个人网站挺炫...想搞一个,一问价格,.,卧槽,,几千..学生哪买的起..想着自己做,买书啊,,看视频啊,,求指点啊..各种途径,最后搞出来了,,后面一段时间,帮别人开发,企业网站,(因为在县级城市,要求不那么高,有个域名,百度能收到,,网站漂亮ok完工.

java小数转换-刚学java的新手遇到的问题

问题描述 刚学java的新手遇到的问题 题目是这样的,编一程序,将摄氏度换为华氏度.公式为:f=c*9/5+32.其中f为华氏度,c为摄氏度. 以下是我的代码 import java.util.*; public class Main{ public static void main (String[] args){ Scanner in1 = new Scanner(System.in); int c =in1.nextInt(); double f = c*9/5+32; System.ou

c++-刚学C++,关于C++类中this指针的疑惑

问题描述 刚学C++,关于C++类中this指针的疑惑 1.我们为什么要学习使用this指针? 2.什么时候使用this指针比较好? (感谢您的回答) 解决方案 this指针的用处: 一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果.this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数.也就是说,即使你没有写上this指针,编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含

java-新人刚学Java,有个很纠结的点求帮忙解答

问题描述 新人刚学Java,有个很纠结的点求帮忙解答 JAVA 在定义一个类时候,在他的内部定义main方法, package com.pc; public class Person { private String name; private String job; private int age; public Person(String name, String job, int age){ this.name = name; this.job = job; this.age = age;

刚学的java,写了个压缩文件的小程序,一直没有成功

问题描述 刚学的java,写了个压缩文件的小程序,一直没有成功 public class f2Test { public static void main(String[] args){ frame02 f2=new frame02(); } } import java.awt.BorderLayout; import java.awt.Color; import java.awt.Image; import java.awt.Menu; import java.awt.MenuBar; imp

刚学c语言出了小问题。。大神棒棒看 谢谢

问题描述 刚学c语言出了小问题..大神棒棒看 谢谢 一个计算日期距离的玩意 #include int sr(); int main() { printf("请输入起始年月日(以回车间隔) "); int memories; int year = sr(); int month = sr(); int day = sr(); printf("请输入当前年月日(以回车间隔) "); int thisyear = sr(); int thismonth = sr(); i

求大神解答跪求-求大神解答,刚学多线程

问题描述 求大神解答,刚学多线程 编写一个多线程程序模拟搬砖过程,用五个线程模拟五个人并行的排成一拍,左边的第一个人左边有无数块砖,要将左边的转依次通过这五个人传到最右边... 解决方案 消息队列.要不给每个砖加锁和加个计数,代表轮到第几个人搬

刚学C#,怎么感觉对数据的处理很弱智?

问题描述 比如说对Datatable有条件的批量修改某列数据VFP可以Replace...for,C#只能循环判断,逐项修改,1万条记录怎么办?有没有快捷点的办法? 解决方案 解决方案二:c#也可以用SQL语句成批修改嘛.解决方案三:datasetlinq解决方案四:那你为什么不用sql批量更新,非得跟datatable较劲呢解决方案五:刚学C#的话,弱智的肯定是你,而不是C#.net解决方案六:该回复于2012-04-05 14:56:31被版主删除解决方案七:各位大神,请问一下,,,repl

我刚学hibernate,请问遇到的一个问题

问题描述 我只是想向数据库中插入一条数据,为什么只插入了一个属性值,另两个是null生成的sql语句为:Hibernate:insertintoStudent(id)values(?)建表代码为:createtablestudent(idintprimarykey,namevachar(20),ageint);然后有一个实体类:Student()privateintid;privateStringname;privateintage;set(),get()都有.Student.hbm.xml配置