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):从线程返回数据的两种方法
从线程中返回数据和向线程传递数据类似.也可以通过类成员以及回调函数来返回数据.但类成员在返回数据和传递数据时有一些区别,下面让我们来看看它们区别在哪. 一.通过类变量和方法返回数据 使用这种方法返回数 ...
随机推荐
- iOS之定位与地图
概览 现在很多社交.电商.团购应用都引入了地图和定位功能,似乎地图功能不再是地图应用 和导航应用所特有的.的确,有了地图和定位功能确实让我们的生活更加丰富多彩,极大的改变了我们的生活方式.例如你到了一 ...
- Android App用MulticastSocket监听组播,为什么连接到不同路由、在不同手机上跑,有的能收到有的收不到
---------------------------!! 转载请注明出处 !!----------------------- 一个项目,利用wifi组播在局域网内发现设备.却发现在有的路由器上能 ...
- UITableViewCell的选中时的颜色及tableViewCell的selecte与deselecte
1.系统默认的颜色设置 //无色 cell.selectionStyle = UITableViewCellSelectionStyleNone; //蓝色 cell.selectionStyle = ...
- 转:通过API获取和创建 Oracle GL Account Code Combination ID’s (CCID’s)的几种方法汇总
1] FND_FLEX_EXT.GET_COMBINATION_ID: This API Finds combination_id for given set of key flexfield seg ...
- maven主仓库中找不到restlet的解决办法
解决办法: 修改Pom.xml 增加 <repositories> <repository> <id>maven-rest ...
- Spring 3.0 + Atomikos构建jta分布式事务
Spring3.0已经不再支持jtom了,不过我们可以用第三方开源软件atomikos(http://www.atomikos.com/)来实现.Atomikos是目前在分布式事务管理中做得相当不错的 ...
- hdu 1563 Find your present!
Find your present! Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- jQuery多图上传Uploadify插件使用及传参详解
因为工作需要,这两天接触到了Uploadify插件,由于是第一次用,花了我近一天的时间.下面我把我在用这个插件过程详细的分享出来,也让自己巩固一下,也希望能帮助到你. 所需文件: jquery-1.8 ...
- Unity3D 之武器系统冷却功能的实现方式
先上方法 //如果Fire1按钮被按下(默认为ctrl),每0.5秒实例化一发子弹 public GameObject projectile; public float fireRate = 0.5F ...
- java 正则表达式匹配字符串
private static List<String> getImage(String str){ List<String> tmp=new ArrayList<Stri ...