小组Java
  • Java 为什么多线程往一个list中放值,但是放值的个数每次都不一样为什么

    2016/09/08 o┢┦apΡy 11 评论

java为什么多线程往一个list中放值,但是放值的个数每次都不一样为什么,不太明白,有的人可能怀疑是因为线程没有跑完,

所以我就DEBUG在list.size那句话之前,这样我可能保证线程都跑完在执行那个list.size然而还是有的情况下丢数据,list的大小每次可能不同。

还有有的人说是因为List是线程不安全的,那我就更不明了了,一个进程下的线程应该都是同一个CPU下的,CPU一个时间片其实也就是执行一个线程,这样不也是一个线程一个线程执行么?list数据不也是一个一个往里面追加么?为什么会丢数据?而且我传入的是引用,他们所找的对象内存空间也是同一个呀?是在是不明白求大神解答一下

1 收藏


直接登录
最新评论
  • Hastings   2016/09/08

    一个进程下的线程应该都是同一个CPU下的,CPU一个时间片其实也就是执行一个线程

    你还没搞懂线程和进程的区别,谁告诉你同一时间下cpu只执行一个线程的?至于为什么会丢数据,你可以想象一下这样一个场景:你有一个账号余500块钱,你往银行存钱,与此同时,有人在异地从你账号里取钱。假设atm机得到你的账户余额,在此余额下加上200,得到一个新的余额700并返回给银行数据中心,另一个人同样提前得到了你账户的余额500,减去两百,atm给银行返回一个余额值300,假设你操作的atm传输速度稍快一点,提前到达,这时候余额是700,但马上,新的信息又把这个数字覆盖为300,那你是不是凭空失去了两百块钱?这就是数据丢失。

    • ?统一时间片内不就只能执行一个线程么?有什么问题??cpu也是以进程为单位的,所以就算是多个核心CPU,java的进程也只会在一个CPU中运行

  • micro 软件攻城狮 2016/09/09

    你让主线程等一下再看结果,启动线程还是用资源开销的。

    • 这个只是测试学习!我想知道的是为什么丢数据,还有我已经说了!我用DEBUG让他们线程都执行完之后再看的结果~~~还是不对

  • 龙雀 野生程序员 2016/09/09

    就算在一个核上,也是存在上下文切换的。例如,你让一个线程死循环,另一个线程还是照样转。

    list的最简实现就是一个底层的固定长度的数组和一个用于维护长度的整数。插入涉及到增加这个整数,由于整数是类的字段,涉及到三个步骤:load、add和store。三个步骤都是原子的,但是整体不是原子的。

    如果,两个线程都在add之后store,那么长度只会增加一,而且两个添加的值都会储存在同一位置。

    • 你的意思是?比如:A线程,和B线程,在A线程得到时间片执行完之后执行到要改list中size这个变量的时候时间片到时间了,也就是被挂起了还没有去改SIZE?之后B线程去执行,可能也没有改SIZE,这样挂起,在第二个时间片周期!A改了SIZE变量,B也改了SIZE变量,但是这个SIZE不是真实的现在的SIZE,只是当时想改的SIZE数,是这个意思么????

      首先我的程序很短,这种一个时间片不能执行完,是不是不太可能,就算可能!那我感觉这样的问题会导致SIZE应该是在50左右,因为都会有这个问题所以应该是真实SIZE的一般,但是现在看来只会出现两种情况一是100,二是99(100是对的)

      • 龙雀 野生程序员 2016/09/10

        任意两个原子操作之间切换都是可能的,虽然你不一定能重现。

  • Hello World 软件工程师 2016/09/10

    你创建了100个线程,每个线程List加入一个数据,然后在main线程中输出List的大小。
    如果100个线程比main线程先运行完,此时输出的是100。
    如果先98个线程先运行完,此时运行main线程,读取的size就会是98,然后剩下的线程再运行。
    你无法保证线程的运行顺序。

  • Forrest 游戏 2016/09/10

    跟人觉得两个问题:

    1,代码中楼主启用了100个线程同时修改list,但是在100个线程启动后,紧接着主线程就开始打印list的大小,并没有保证其他子线程全部完成,那就会出现如下情况,当第100个子线程(假如它最后执行add)还未来得及修改list的内存时,主线程已经在读取list所在内存的数据,那么此时list中还有一个元素没有加入

    2,再说arraylist的线程不安全,arraylist的源码大概就是一个array,一个size,当调用add时,大概的过程就是:ensureCapacity(); array[size]=newData; size=size+1;很显然cpu想完成add方法至少需要执行3条指令,指令应该是cpu的最小执行单位(不知道这里说的准不准确),如楼主所言如果cpu一个时间片执行一个线程,那么很可能上一个时间片执行的是1线程第一条指令,下一个时间片可能分配给另一个线程执行第二条指令,此时size并未改变,那么数组的同一个索引很有可能被两个线程修改,两个线程修改同一个内存地址,那么最终数组的大小肯定不是100啦

    不过上面的讲述带有一定的误导,因为size()方法最终取得其实就是size的值,其实楼主可以这么理解,就是两个线程同时调用add时,虽然肯定有先后顺序,但由于add方法并不是原子的,所以1线程调用add时size的值不会立刻就被改变了,2线程来取值时很有可能和1线程取到同一个值,那最终导致的就是两个线程只修改了size一次,100个线程每个线程为size加一最终是100, 但是如果其中两个线程只改变size一次,那最终结果就是99啦

    纯属个人见解