Java多线程初学者指南(6):慎重使用volatile关键字
volatile关键字相信了解Java多线程的读者都很清楚它的作用,和sychnorized 一样用于多线程的同步。volatile关键字用于声明简单类型变量,如int、float、boolean等数据类型(synchronized 用于方法或者代码段)。如果这些简单数据类型声明为volatile,对它们的操作就会变成原子级别的。但这有一定的限制。例如,下面的例子中的n就不是原子级别的:
package mythread; public class JoinThread extends Thread
{
public static volatile int n = 0;
public void run()
{
for (int i = 0; i < 10; i++)
try
{
n = n + 1;
sleep(3); // 为了使运行结果更随机,延迟3毫秒 }
catch (Exception e)
{
}
} public static void main(String[] args) throws Exception
{ Thread threads[] = new Thread[100];
for (int i = 0; i < threads.length; i++)
// 建立100个线程
threads[i] = new JoinThread();
for (int i = 0; i < threads.length; i++)
// 运行刚才建立的100个线程
threads[i].start();
for (int i = 0; i < threads.length; i++)
// 100个线程都执行完后继续
threads[i].join();
System.out.println("n=" + JoinThread.n);
}
}
如果对n的操作是原子级别的,最后输出的结果应该为n=1000,而在执行上面积代码时,很多时侯输出的n都小于1000,这说明n=n+1不是原子级别的操作。原因是声明为volatile的简单变量如果当前值由该变量以前的值相关,那么volatile关键字不起作用,也就是说如下的表达式都不是原子操作:
n = n + 1; n++;
如果要想使这种情况变成原子操作,需要使用synchronized关键字,如上的代码可以改成如下的形式:
package mythread; public class JoinThread extends Thread
{
public static int n = 0; public static synchronized void inc()
8 {
9 n++;
10 }
public void run()
{
for (int i = 0; i < 10; i++)
try
{
inc(); // n = n + 1 改成了 inc();
sleep(3); // 为了使运行结果更随机,延迟3毫秒 }
catch (Exception e)
{
}
} public static void main(String[] args) throws Exception
{ Thread threads[] = new Thread[100];
for (int i = 0; i < threads.length; i++)
// 建立100个线程
threads[i] = new JoinThread();
for (int i = 0; i < threads.length; i++)
// 运行刚才建立的100个线程
threads[i].start();
for (int i = 0; i < threads.length; i++)
// 100个线程都执行完后继续
threads[i].join();
System.out.println("n=" + JoinThread.n);
}
}
上面的代码将n=n+1改成了inc(),其中inc方法使用了synchronized关键字进行方法同步。因此,在使用volatile关键字时要慎重,并不是只要简单类型变量使用volatile修饰,对这个变量的所有操作都是原来操作,当变量的值由自身的上一个决定时,如n=n+1、n++等,volatile关键字将失效,只有当变量的值和自身上一个值无关时对该变量的操作才是原子级别的,如n = m + 1,这个就是原级别的。所以在使用volatile关键时一定要谨慎,如果自己没有把握,可以使用synchronized来代替volatile。
Java多线程初学者指南(6):慎重使用volatile关键字的更多相关文章
- Java多线程初学者指南系列教程
转自:http://developer.51cto.com/art/200911/162925.htm 51cto 本系列来自NokiaGuy的“真的有外星人吗”博客,系列名称为<Java多线程 ...
- 【系列】Java多线程初学者指南(1):线程简介
原文地址:http://www.blogjava.net/nokiaguy/archive/2009/nokiaguy/archive/2009/03/archive/2009/03/19/26075 ...
- Java多线程干货系列—(四)volatile关键字
原文地址:http://tengj.top/2016/05/06/threadvolatile4/ <h1 id="前言"><a href="#前言&q ...
- Java多线程初学者指南(7):向线程传递数据的三种方法
在传统的同步开发模式下,当我们调用一个函数时,通过这个函数的参数将数据传入,并通过这个函数的返回值来返回最终的计算结果.但在多线程的异步开发模式下,数据的传递和返回和同步开发模式有很大的区别.由于线程 ...
- Java多线程初学者指南(4):线程的生命周期
与人有生老病死一样,线程也同样要经历开始(等待).运行.挂起和停止四种不同的状态.这四种状态都可以通过Thread类中的方法进行控制.下面给出了Thread类中和这四种状态相关的方法. // 开始线程 ...
- Java多线程初学者指南(12):使用Synchronized块同步变量
我们可以通过synchronized块来同步特定的静态或非静态方法.要想实现这种需求必须为这些特性的方法定义一个类变量,然后将这些方法的代码用synchronized块括起来,并将这个类变量作为参数传 ...
- Java多线程初学者指南(10):使用Synchronized关键字同步类方法
要想解决“脏数据”的问题,最简单的方法就是使用synchronized关键字来使run方法同步,代码如下: public synchronized void run() { ... } 从上面的代码可 ...
- Java多线程初学者指南(9):为什么要进行数据同步
Java中的变量分为两类:局部变量和类变量.局部变量是指在方法内定义的变量,如在run方法中定义的变量.对于这些变量来说,并不存在线程之间共享的问题.因此,它们不需要进行数据同步.类变量是在类中定义的 ...
- Java多线程初学者指南(8):从线程返回数据的两种方法
从线程中返回数据和向线程传递数据类似.也可以通过类成员以及回调函数来返回数据.但类成员在返回数据和传递数据时有一些区别,下面让我们来看看它们区别在哪. 一.通过类变量和方法返回数据 使用这种方法返回数 ...
随机推荐
- WPF 自定义路由事件 与 附加路由事件
为student添加附件事件
- 练习PopupWindow弹出框之实现界面加载的时候显示弹出框到指定的view下面--两种延迟方法
今天在练习PopupWindow弹出框的时候,打算在界面加载的时候将弹出框展现出来并显示在指定的view下面. 初步方法是直接在OnResume方法里面直接执行showPopupWindows方法. ...
- java与.net平台之间进行RSA加密验证
RSA加密算法虽然不分平台,标准都是一样的,但是各个平台的实现方式都不尽相同,下面来我来说说java与.net平台之间该如何进行RSA加密验证,即java端加密->.net端验证和.net端加密 ...
- union的用法
union的用法 union用来连接两个查询语句,把两个查询语句的查询结果合并起来,两个查询语句的查询字段个数必须一样,否则会出错,查询的字段可以不一样,类型也可以不一样,但是这样查询的意义不大,如果 ...
- jqery选择器
根据可见性 属性 匹配元素 <!doctype html> <html lang="en"> <head> <meta charset=& ...
- ABI Management
官方文档:https://developer.android.com/ndk/guides/abis.html?hl=is 关于支持指令集,在上表官方文档都表达清楚了.我们认为避免多个指令集浪费资源. ...
- Linq 与UnitOfWork
submitchages(linq to sql)或者savechanges(ef)的次数是根据你操作方法的数量决定的,也即是:它只认识自己的提交语句(submtchanges,savechanges ...
- WKWebView详解
WKWebView是在Apple的WWDC 2014随iOS 8和OS X 10.10出来的,是为了解决UIWebView加载速度慢.占用内存大的问题.使用UIWebView加载网页的时候,我们会发现 ...
- 使用NPOI操作Excel
案例:用NPOI动态生成一个Excel表,然后弹出对话框让用户下载,文件名是"用户列表.xls" 先去相关网站下载 NPOI DLL文件,再引用 application/x-e ...
- J2EE中的HttpSession
J2EE中的HttpSession总结: ①什么是session? session是服务器端技术,利用这个技术,服务器在运行时可以为每一个浏览器创建一个共享的session对象,由于 session为 ...