java volatile synchronized关键字使用问题

题目描述
在学习多线程的知识,下面的代码跑出的结果与预想的不一致,看不明白问题出在哪里,麻烦大家帮忙看看
题目来源及自己的思路
我想的是程序结束后staticv的值是个整数200000,但是每次结果都在19xxxxxxx,离的很近,又不像同步出了问题,不知是哪里出了问题,另外代码注释标注为#的位置,foo被synchronized标志,那同步的是SyncObj的实例对象而不是SyncObjc.class,明明是两个实例对象在被调用没有加同步,我以为volatile没加上去结果是错误的,但执行的结果好像没区别,为什么?我不清楚我的理解哪里出了问题,请大家多多指教,谢谢。
相关代码
packageconcurrency;
importjava.util.concurrent.CountDownLatch;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importjava.util.concurrent.TimeUnit;
publicclassSynchronizedTest{
publicstaticvoidmain(String[]args)throwsInterruptedException{
ExecutorServiceexecutor=Executors.newCachedThreadPool();
SyncObjobj1=newSyncObj();
SyncObjobj2=newSyncObj();
CountDownLatchcountDownLatch=newCountDownLatch(20);
for(inti=0;i<10;i++){
executor.execute(newTT(obj1,countDownLatch));
executor.execute(newTT(obj2,countDownLatch));
}
countDownLatch.await();
System.out.println("result----------------------"+SyncObj.staticv);
}
}
classSyncObj{
publicstaticvolatileintstaticv=0;//######volatile是不是可有可无?
publicsynchronizedvoidfoo(){
for(inti=0;i<1000;i++){
System.out.println(staticv);
staticv++;
}
}
}
classTTimplementsRunnable{
publicCountDownLatchcountDownLatch;
publicSyncObjobj;
publicTT(SyncObjobj,CountDownLatchcountDownLatch){
this.obj=obj;
this.countDownLatch=countDownLatch;
}
@Override
publicvoidrun(){
for(inti=0;i<100;i++){
obj.foo();
}
countDownLatch.countDown();
}
}
30秒到达战场
浏览 443回答 2
2回答

猛跑小猪

出现问题的原因是volatile不提供原子性。staticv++;实际上是读取-修改-写入操作序列组成的组合操作。假如线程A和线程B同时执行staticv++;,线程A读取staticv的值,加1,然后中断,接着线程B读取staticv的值,加1,然后写入staticv。此时线程A接着执行,虽然根据volatile的特性,线程A中staticv的值已经变成+1之后的值,但是此时线程A已经不会重新读取staticv了,而是直接把原来读取的staticv加1之后的值回写到staticv上,导致虽然执行了两遍staticv++;,但是其实staticv只增加了1。我们再来讨论为什么把staticv++;用synchronized包起来之后还是没有实现staticv自增原子性的效果。这个问题的关键是你把synchronized用到了方法级别。你申请了两个SyncObj的对象出来,这两个对象的foo方法之间是没有同步关系的,同步关系只在同一个对象的foo方法中有。如果把foo方法改成这样就是正确的了。publicvoidfoo(){synchronized(this.getClass()){for(inti=0;i
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript