volatile关键字相信了解Java多线程的读者都很清楚它的作用。volatile关键字用于声明简单类型变量,如int、float、boolean等数据类型。如果这些简单数据类型声明为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() { 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 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。

慎重使用volatile关键字的更多相关文章

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

    volatile关键字相信了解Java多线程的读者都很清楚它的作用,和sychnorized 一样用于多线程的同步.volatile关键字用于声明简单类型变量,如int.float.boolean等数 ...

  2. java多线程-慎重使用volatile关键字

    Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量.这两种机制的提出都是为了实现代码线程的安全性.其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而 ...

  3. java 轻量级同步volatile关键字简介与可见性有序性与synchronized区别 多线程中篇(十二)

    概念 JMM规范解决了线程安全的问题,主要三个方面:原子性.可见性.有序性,借助于synchronized关键字体现,可以有效地保障线程安全(前提是你正确运用) 之前说过,这三个特性并不一定需要全部同 ...

  4. java内存模型(线程,volatile关键字和sychronized关键字)

    volatile关键字 用在多线程,同步变量. 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B.只在某些动作时才进行A和B的同步.因此存在A和B不一致的情况. ...

  5. Java并发编程:volatile关键字解析

    Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...

  6. volatile关键字 学习记录2

    public class VolatileTest2 implements Runnable{ volatile int resource = 0; public static void main(S ...

  7. volatile关键字 学习记录1

    虽然已经工作了半年了...虽然一直是在做web开发....但是平时一直很少使用多线程..... 然后最近一直在看相关知识..所以就有了这篇文章 用例子来说明问题吧 public class Volat ...

  8. 【转】Java并发编程:volatile关键字解析

    转自:http://www.importnew.com/18126.html#comment-487304 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备 ...

  9. 架构师养成记--4.volatile关键字

    volatile修饰的变量可在多个线程间可见. 如下代码,在子线程运行期间主线程修改属性值并不对子线程产生影响,原因是子线程有自己独立的内存空间,其中有主内存中的变量副本. public class ...

随机推荐

  1. css3 :nth-child()选择器的使用

    一.nth-child() 1. nth-child(n):父元素下的第n个子元素,n>0,索引从1开始.不区分子元素类型. 2. nth-child(odd):父元素下的奇数子元素,等同于:n ...

  2. Ubuntu django+nginx 搭建python web服务器文件日志

    uwsgi 配置文件 [uwsgi] http-socket = 127.0.0.1:8080 # 项目目录 chdir=/home/ubuntu/mkweb # 指定项目的application m ...

  3. [整理]CSS3 滤镜

    1.灰度 兼容 http://www.526net.com/blog/qianduan/226.html http://james.padolsey.com/demos/grayscale/grays ...

  4. TED_Topic7:How we unearthed the spinosaurus

    By Nizar Ibrahim A 50-foot-long carnivore who hunted its prey in rivers 97 million years ago, the sp ...

  5. es6笔记(1) 概要

    什么是ES6 ECMAScript 6.0 (简称ES6) 是继ECMAScript 5.1以后的javascript 语言的下一代标准,在2015年6月份发布. 他的目标是使javascript语言 ...

  6. Docker学习笔记一 概念、安装、镜像加速

    本文地址:https://www.cnblogs.com/veinyin/p/10406378.html  Docker 是一个容器,可以想象成一个轻便的虚拟机,但不虚拟硬件和操作系统. 优点:启动快 ...

  7. 重启虚拟目录或站点,不重启iis

    更改站点或虚拟目录的.net Framework 版本会导致重启整个iis服务,所以需要单独重启某个站点或虚拟目录 首先右键点击网站-所有任务-将配置保存到一个文件,从文件中查找到 Location ...

  8. perl6 中将 字符串 转成十六进制

    say Blob.new('abcde'.encode('utf8')).unpack("H*"); say '0x'~'abcde'.encode('utf8').unpack( ...

  9. MYSQL问题解决

    1. MySQL错误日志里出现: 140331 10:08:18 [ERROR] Error reading master configuration 140331 10:08:18 [ERROR] ...

  10. linux网桥浅析

    linux网桥浅析 原文链接:http://hi.baidu.com/_kouu/item/25787d38efec56637c034bd0 什么是桥接?简单来说,桥接就是把一台机器上的若干个网络接口 ...