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

  1. public class JoinThread extends Thread {
  2.  
  3. public static volatile int n = 0;
  4. public void run() {
  5. for (int i = 0; i < 10; i++) {
  6. try {
  7. n = n + 1;
  8. sleep(3);// 为了使运行结果更随即,延迟3毫秒
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. }
  13. }
  14.  
  15. // public static int n = 0;
  16. //
  17. // public static synchronized void inc() {
  18. // n++;
  19. // }
  20. //
  21. // public void run() {
  22. // for (int i = 0; i < 10; i++) {
  23. // try {
  24. // inc();// n=n+1改成了inc()
  25. // sleep(3);// 为了使运行结果更随即,延迟3毫秒
  26. // } catch (InterruptedException e) {
  27. // e.printStackTrace();
  28. // }
  29. // }
  30. // }
  31.  
  32. public static void main(String[] args) throws InterruptedException {
  33. int t = 1000;
  34. int p = 0;
  35. while (t == 1000 && p < 1000) {
  36. System.out.println("n=" + JoinThread.n);
  37. Thread threads[] = new Thread[100];
  38. for (int i = 0; i < threads.length; i++) {
  39. // 建立100个线程
  40. threads[i] = new JoinThread();
  41. }
  42.  
  43. for (int i = 0; i < threads.length; i++) {
  44. // 运行刚才建立的100个线程
  45. threads[i].start();
  46. }
  47.  
  48. for (int i = 0; i < threads.length; i++) {
  49. // 100个线程都执行完后继续
  50. threads[i].join();
  51. }
  52.  
  53. System.out.println("n=" + JoinThread.n);
  54. t = JoinThread.n;
  55. p++;
  56. JoinThread.n=0;
  57. }
  58.  
  59. System.out.println("n=" + JoinThread.n);
  60. System.out.println("p=" + p);
  61.  
  62. }
  63. }

执行结果如下所示:

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

n = n + 1;
        n++;

如果要想使这种情况变成原子操作,需要使用synchronized关键。将如下代码注释掉,并将原来注释的代码恢复,重新执行程序。

public static volatile int n = 0;
  public void run() {
   for (int i = 0; i < 10; i++) {
    try {
     n = n + 1;
     sleep(3);// 为了使运行结果更随即,延迟3毫秒
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
  }

得到执行结果如下:

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

文章转自:http://longshuai2007.blog.163.com/blog/static/14209441420116214435199/

volatile与synchronized关键字的更多相关文章

  1. 从JAVA看C#中volatile和synchronized关键字的作用

    最近一直在想C#中 volatile关键字到底是用来干什么的?查了很多.NET的文章都是说用volatile修饰的变量可以让多线程同时修改,这是什么鬼... 然后查到了下面这篇JAVA中关于volat ...

  2. volatile和synchronized关键字

    synchronized java课上讲到过synchronized 首先看看用synchronized和没用synchronized的区别 import lombok.Getter; /** * @ ...

  3. 《Java基础知识》Java锁详解(volatile,synchronized等)

    volatile: 让变量每次在使用的时候,都从主存中取. volatile具有synchronized关键字的“可见性”,但是没有synchronized关键字的“并发正确性”,也就是说不保证线程执 ...

  4. java中的volatile和synchronized

    关于volatile和同步相关的东西,网上有太多错误和解释不清的东西, 所以查阅相关书籍和文章后总结如下, 如果还是也存在不正确的内容,请一定要指出来, 以免误人子弟:) 1. 原子性与可视性 原子性 ...

  5. volatile和synchronized到底啥区别?多图文讲解告诉你

    你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough ...

  6. volatile关键字和synchronized关键字

    volatile关键字: 可以用来修饰字段(成员变量),就是告知程序任何对该变量的访问均需要从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性. synchron ...

  7. 并发编程之ThreadLocal、Volatile、synchronized、Atomic关键字扫盲

    前言 对于ThreadLocal.Volatile.synchronized.Atomic这四个关键字,我想一提及到大家肯定都想到的是解决在多线程并发环境下资源的共享问题,但是要细说每一个的特点.区别 ...

  8. 并发系列2:Java并发的基石,volatile关键字、synchronized关键字、乐观锁CAS操作

    由并发大师Doug Lea操刀的并发包Concurrent是并发编程的重要包,而并发包的基石又是volatile关键字.synchronized关键字.乐观锁CAS操作这些基础.因此了解他们的原理对我 ...

  9. 多线程的指令重排问题:as-if-serial语义,happens-before语义;volatile关键字,volatile和synchronized的区别

    一.指令重排问题 你写的代码有可能,根本没有按照你期望的顺序执行,因为编译器和 CPU 会尝试指令重排来让代码运行更高效,这就是指令重排. 1.1 虚拟机层面 我们都知道CPU执行指令的时候,访问内存 ...

随机推荐

  1. 【NOIP训练】【Tarjan求割边】上学

    题目描述 给你一张图,询问当删去某一条边时,起点到终点最短路是否改变. 输入格式 第一行输入两个正整数,分别表示点数和边数.第二行输入两个正整数,起点标号为,终点标号为.接下来行,每行三个整数,表示有 ...

  2. KMP---Count the string

    题目网址:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=110060#problem/A Description It is well k ...

  3. 控制台(Console)报错:java.io.IOException: Broken pipe

    控制台(Console)输出: java.io.IOException: Broken pipe at sun.nio.ch.FileDispatcherImpl.write0(Native Meth ...

  4. HTML5中的音视频处理

    * 音视频处理 * 视频处理 * 基本内容 * 使用Flash技术处理HTML页面中的视频内容 * 包含音频.动画.网页游戏等 * 特点 * 浏览器原生不支持(IE浏览器要求安装ActiveX组件) ...

  5. 与成都的幸福行动家交流GTD

    今年第四次来成都了,通过<小强升职记>的作者邹鑫的撮合,与成都的幸福行动家何平取得了联系,2014年12月6日下午给几个小伙伴们分享了GTD3年来的一点体会.有几位刚接触GTD的朋友,也有 ...

  6. 浅谈PopupWindow弹出菜单

    实现将一个View显示在某一位置,而且是浮于当前窗口 首先要有一个要显示的view的布局,可以是任意View,包括ViewGroup <?xml version="1.0" ...

  7. iOS 简单工厂模式

    iOS 简单工厂模式 什么是简单工厂模式? 简单工厂模式中定义一个抽象类,抽象类中声明公共的特征及属性,抽象子类继承自抽象类,去实现具体的操作.工厂类根据外界需求,在工厂类中创建对应的抽象子类实例并传 ...

  8. IOS 杂笔-4(属性与成员变量的区别)

    属性可以用点语法,比如self.xxx,在外部调用也同样可以someClass.xxx. 属性实际上是对一组set和get方法的简单封装(oc的get方法没有get前缀),同样会自动生成一个私有的成员 ...

  9. 保持listview当前位置

    保持listview滑动的位置,一般用在增加listview子item中布局的评论或者退出当前活动,再次进入继续阅读时. 利用ListView.getFirstVisiblePosition()来获取 ...

  10. C++语言-03-类与对象

    类 类是面向对象编程中的核心概念,用于定义一个数据类型的蓝图,描述类的对象包括什么,以及可以在这些对象上执行那些操作. 类的成员 数据成员 描述数据的表示方法 class ClassName { ac ...