打字猴:1.700450339e+09
1700450339
1700450340 }
1700450341
1700450342 //先等15毫秒,等待活动线程数量成为1
1700450343
1700450344 do{
1700450345
1700450346 Thread.sleep(15);
1700450347
1700450348 }while(tg.activeCount()!=1);
1700450349
1700450350 //检查实际值与理论值是否一致
1700450351
1700450352 if(ut.getCount()!=value){
1700450353
1700450354 //出现线程不安全的情况
1700450355
1700450356 System.out.println(“循环到第”+loops+“遍,出现线程不安全情况”);
1700450357
1700450358 System.out.println(“此时,count=”+ut.getCount());
1700450359
1700450360 System.exit(0);
1700450361
1700450362 }
1700450363
1700450364 }
1700450365
1700450366 }
1700450367
1700450368 这是一段设计很巧妙的程序,要让volatile变量“出点丑”还是需要花点功夫的。此段程序的运行逻辑如下:
1700450369
1700450370 启动100个线程,修改共享资源count的值。
1700450371
1700450372 暂停15毫秒,观察活动线程数是否为1(即只剩下主线程在运行),若不为1,则再等待15毫秒。
1700450373
1700450374 判断共享资源是否是不安全的,即实际值与理想值是否相同,若不相同,则发现目标,此时count的值为脏数据。
1700450375
1700450376 如果没有找到,继续循环,直到达到最大循环次数为止。运行结果如下:
1700450377
1700450378 循环到第247遍,出现线程不安全情况
1700450379
1700450380 此时,count=999
1700450381
1700450382 这只是一种可能的结果,每次执行都有可能产生不同的结果。这也说明我们的count变量没有实现数据同步,在多个线程修改的情况下,count的实际值与理论值产生了偏差,直接说明了volatile关键字并不能保证线程安全。
1700450383
1700450384 在解释原因之前,我们先说一下自加操作。count++表示的是先取出count的值然后再加1,也就是count=count+1,所以,在某两个紧邻的时间片段内会发生如下神奇的事情:
1700450385
1700450386 (1)第一个时间片段
1700450387
1700450388 A线程获得执行机会,因为有关键字volatile修饰,所以它从主内存中获得count的最新值998,接下来的事情又分为两种类型:
[ 上一页 ]  [ :1.700450339e+09 ]  [ 下一页 ]