java多线程-慎重使用volatile关键字
Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。
public volatile boolean exit = false;
在定义exit时,使用了一个Java关键字volatile,这个关键字的目的是使exit同步,也就是说在同一时刻只能由一个线程来修改exit的值.
volatile关键字用于声明简单类型变量,如int、float、boolean等数据类型。如果这些简单数据类型声明为volatile,对它们的操作就会变成原子级别的。但这有一定的限制。例如,下面的例子中的n就不是原子级别的:
package junit.test;
public class ThreadVolatile 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 ThreadVolatile();
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=" + ThreadVolatile.n);
}
}
如果对n的操作是原子级别的,最后输出的结果应该为n=1000,而在执行上面代码时,很多时侯输出的n都小于1000,这说明n=n+1不是原子级别的操作。原因是声明为volatile的简单变量如果当前值由该变量以前的值相关,那么volatile关键字不起作用,也就是说如下的表达式都不是原子操作:
n = n + 1;
n++;
如果要想使这种情况变成原子操作,需要使用synchronized关键字,如上的代码可以改成如下的形式:
package junit.test;
public class ThreadVolatile2 extends Thread {
public static volatile int n = 0;
public static synchronized void inc() {
n++;
}
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 ThreadVolatile2();
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=" + ThreadVolatile2.n);
}
}
上面的代码将n=n+1改成了inc(),其中inc方法使用了synchronized关键字进行方法同步。因此,在使用volatile关键字时要慎重,并不是只要简单类型变量使用volatile修饰,对这个变量的所有操作都是原来操作,当变量的值由自身的上一个决定时,如n=n+1、n++等,volatile关键字将失效,只有当变量的值和自身上一个值无关时对该变量的操作才是原子级别的,如n = m + 1,这个就是原级别的。所以在使用volatile关键时一定要谨慎,如果自己没有把握,可以使用synchronized来代替volatile。
java多线程-慎重使用volatile关键字的更多相关文章
- java多线程4:volatile关键字
上文说到了 synchronized,那么就不得不说下 volatile关键字了,它们两者经常协同处理多线程的安全问题. volatile保证可见性 那么volatile的作用是什么呢? 在jvm运行 ...
- java 多线程11:volatile关键字
直接先举一个例子普通的线程实例变量的非可见性: public class MyThread28 extends Thread { private boolean isRunning = true; p ...
- Java并发编程:volatile关键字解析
Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...
- 【转】Java并发编程:volatile关键字解析
转自:http://www.importnew.com/18126.html#comment-487304 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备 ...
- (转)Java并发编程:volatile关键字解析
转:http://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或 ...
- 《转》JAVA并发编程:volatile关键字解析
volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ...
- 【转载】Java并发编程:volatile关键字解析(写的非常好的一篇文章)
原文出处: 海子 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volat ...
- Java并发编程:volatile关键字解析(转载)
转自https://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 Java并发编程:volatile关键字解析 ...
- Java并发编程:volatile关键字解析zz
volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ...
随机推荐
- Spring-Java事物回滚失效处理
spring-Java事物回滚失效处理最近在做项目中,无意间发现有个类在抛事物回滚操作,数据也正常的插入到数据库当中了,于是仔细查看看一下具体原因. 一切还是要从Java的检查型异常和非检查型异常说起 ...
- WCF Restful Post调用
一.首先建立Http的服务端,此示例的寄宿体为WindowsService,以下代码仅为WCF Restful服务代码,不包括服务启动和安装代码 1.服务契约 /// <summary> ...
- Numpy, Pandas, Matplotlib, Scipy 初步
Numpy: 计算基础, 以类似于matlab的矩阵计算为基础. 底层以C实现, 速度快. Pandas: 以numpy为基础, 扩充了很多统计工具. 重点是数据统计分析. Matplotlib: ...
- Android.mk用法详解
一.Android.mk介绍 Android.mk是Android提供的一种makefile文件,用来指定诸如编译生成so库名.引用的头文件目录.需要编译的.c/.cpp文件和.a静态库文件等.要掌握 ...
- quick3.3rc1导入工程到ADT
1.libcocos2dx 路径到/quick-3.3rc1/cocos/platform/android/java这一层 2.quick项目 路径到D:\codeide\test11\framew ...
- 笔记:NPM 无限需要依赖问题解决
笔记:NPM 无限需要依赖问题解决 起因 因为想学一下 VUE,开始跟着教程一步一步输出命令,开始也没有什么问题,一切都很顺利. 突然不知道是哪一步出了问题,一直让我安装依赖,没完没了,开始并不觉得有 ...
- 机器学习之代价函数(cost function)
代价函数(有的地方也叫损失函数,Loss Function)在机器学习中的每一种算法中都很重要,因为训练模型的过程就是优化代价函数的过程,代价函数对每个参数的偏导数就是梯度下降中提到的梯度,防止过拟合 ...
- java 重写 与 重载 用法
图例: 重写: 其实就是获取其他类 和自己类相同的方法名 来使用 重载: 其实就是创建多个相同的方法名,里面装载不同的参数 重写例子: Super关键字 重载的例子:
- Docker - 记录在window 上的一些“坑”
前言 由于领导要在超极本上面演示一些东西,所以决定在window平台上面使用docker,于是乎,便有了下面的一些故事... CPU / Memery 的总体设置 众所周知,在Linux上面使用doc ...
- mysql导出文本文件,加分隔符
从mysql导出,再导入到oracle #!/bin/sh cd /u03/tools/machine_info rm -f data/machine_info.txt mysql -u用户名 -p密 ...