java

位置:IT落伍者 >> java >> 浏览文章

Java多线程初学者指南(6):慎重使用volatile关键字


发布日期:2021年05月31日
 
Java多线程初学者指南(6):慎重使用volatile关键字

volatile关键字相信了解Java多线程的读者都很清楚它的作用volatile关键字用于声明简单类型变量如intfloatboolean等数据类型如果这些简单数据类型声明为volatile对它们的操作就会变成原子级别的但这有一定的限制例如下面的例子中的n就不是原子级别的

packagemythread;

publicclassJoinThreadextendsThread

{

publicstatic volatile intn=;

publicvoidrun()

{

for(inti=;i<;i++)

try

{

n=n+;

sleep();//为了使运行结果更随机延迟毫秒

}

catch(Exceptione)

{

}

}

publicstaticvoidmain(String[]args)throwsException

{

Threadthreads[]=newThread[];

for(inti=;i<threadslength;i++)

//建立个线程

threads[i]=newJoinThread();

for(inti=;i<threadslength;i++)

//运行刚才建立的个线程

threads[i]start();

for(inti=;i<threadslength;i++)

//个线程都执行完后继续

threads[i]join();

Systemoutprintln(n=+JoinThreadn);

}

}

如果对n的操作是原子级别的最后输出的结果应该为n=而在执行上面积代码时很多时侯输出的n都小于这说明n=n+不是原子级别的操作原因是声明为volatile的简单变量如果当前值由该变量以前的值相关那么volatile关键字不起作用也就是说如下的表达式都不是原子操作

n=n+;

n++;

如果要想使这种情况变成原子操作需要使用synchronized关键字如上的代码可以改成如下的形式

packagemythread;

publicclassJoinThreadextendsThread

{

publicstatic intn=;

public staticsynchronizedvoidinc()

{

n++;

}

publicvoidrun()

{

for(inti=;i<;i++)

try

{

inc();//n=n+改成了inc();

sleep();//为了使运行结果更随机延迟毫秒

}

catch(Exceptione)

{

}

}

publicstaticvoidmain(String[]args)throwsException

{

Threadthreads[]=newThread[];

for(inti=;i<threadslength;i++)

//建立个线程

threads[i]=newJoinThread();

for(inti=;i<threadslength;i++)

//运行刚才建立的个线程

threads[i]start();

for(inti=;i<threadslength;i++)

//个线程都执行完后继续

threads[i]join();

Systemoutprintln(n=+JoinThreadn);

}

}

上面的代码将n=n+改成了inc()其中inc方法使用了synchronized关键字进行方法同步因此在使用volatile关键字时要慎重并不是只要简单类型变量使用volatile修饰对这个变量的所有操作都是原来操作当变量的值由自身的上一个决定时如n=n+n++等volatile关键字将失效只有当变量的值和自身上一个值无关时对该变量的操作才是原子级别的如n = m + 这个就是原级别的所以在使用volatile关键时一定要谨慎如果自己没有把握可以使用synchronized来代替volatile

               

上一篇:Java多线程同步如何从JVM的角度体会

下一篇:Java多线程编程的常见陷阱