volatile关键字的介绍和使用
来源:互联网 发布:网络机顶盒价格 编辑:程序博客网 时间:2024/05/29 16:40
关键字volatile的主要作用是使变量在过个线程中可见
1、假设volatile不存在我们将会面对的问题
public class PrintString implements Runnable{ private boolean isContinuePrint = true; public boolean isContinuePrint() { return isContinuePrint; } public void setContinuePrint(boolean isContinuePrint) { this.isContinuePrint = isContinuePrint; } public void printStringMethod() { try { while(isContinuePrint) { System.out.println("run printStringMethod threadName = " + Thread.currentThread().getName()); Thread.sleep(1000); } } catch(InterruptedException exception) { exception.printStackTrace(); } } @Override public void run() { printStringMethod(); }}
public class Test { /** * @param args */ public static void main(String[] args) { try { PrintString mPrintString = new PrintString(); Thread mThread = new Thread(mPrintString); mThread.start(); Thread.sleep(1000); mPrintString.setContinuePrint(false);//在-server模式下,这个操作修改的是公共堆栈中的值,而线程的私有堆栈并没有修改 } catch(InterruptedException e) { e.printStackTrace(); } }}
当JVM 在-server模式下并不会停止PrintString的method,因为在-server的模式下存在一个公共堆栈和线程私有堆栈的概念。我们在调用setConinuePrinter(false)修改的是公共堆栈中的值,并不会影响到线程的私有堆栈。
此时我们需要引入volatile关键字,作用是强制线程去公共堆栈中访问isContinuePrint的值。
使用volatile关键字增加了实例变量在多个线程之间的可见性,但volatile关键字有一个致命的缺陷是不支持原子性
synchronized与volatile关键字之间的比较
- 关键字volatile是线程同步的轻量实现,所以volatile关键字性能比synchronized好。volatile只能修饰变量,synchronized可以修饰方法,代码块
- volatile不会阻塞线程,synchronized会阻塞线程
- volatile能保证数据的可见性,不保证原子性,synchronized可以保证原子性,可以间接保证可见性,它会将公共内存和私有内存的数据做同步处理。
- volatile解决的是变量在多个线程之间的可见性,synchronized解决的是多个线程之间访问资源的同步性
请记住Java的同步机制都是围绕两点:原子性,线程之间的可见性.只有满足了这两点才能称得上是同步的。Java中的synchronized和volatile两个关键字分别执行的是原子性和线程之间的可见性。
volatile 并非原子性
看一个例子
package com.sophia.demo;public class MyThread extends Thread{ volatile public static int COUNT; private static void addCount() { for (int i = 0; i < 100; i++) { COUNT++; } System.out.println("count = " + COUNT); } @Override public void run() { addCount(); }}
package com.sophia.demo;public class StringTest { public static void main(String[] args) { MyThread[] myThreads = new MyThread[100]; for (int i = 0; i < myThreads.length; i++) { myThreads[i] = new MyThread(); } for (MyThread myThread : myThreads) { if (null != myThread) { myThread.start(); } } }}
输出的结果并不如我们想象中的那样子递增
count = 200count = 300count = 200
仔细观察输出结果中我们看到有这样子一段结果,当我们在addCount()方法中加上synchronized方法就能达到同步的效果。此时就没必要使用volatile关键字了。
首先我们来分析一个常见的表达式i++即i = i + 1;这个操作不是原子性也就是非线程安全的,分解的步骤如下
- 从内存中取出i的值
- 计算i的值
- 将i的值写入内存中
假设在执行第2步的时候,有其他线程在修改i的值,这个时候就会出现脏数据,解决的办法就是使用synchronized关键字。所以说volatile并不处理数据的原子性
详细解释一下volatile出现线程不安全的原因:
- read和load过程:从主存中复制变量到当前线程的工作内存中
- use和assign过程:执行代码,更改变量的值
- store和write过程:存储更改后的变量,并写入主存。
在多线程换种中,use和assign是多次出现的,但这一操作并不是原子性,也就是在read和load之后,如果主内存count变量发送修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化,也就是私有内存和公共内存的值不一样。此时其他线程在去取公共内存的值就会造成偏差。导致线程不安全。所以多个线程访问同一个变量加锁才是最安全的操作。
Java提供了一个线程安全的Integer类,AtomicInteger,原子操作是不可分割的整体,没有其他线程能够终端或检查正在原子操作中的变量,可以在没有锁的情况下做到线程安全
- volatile关键字的介绍和使用
- 转:关键字Const和Volatile的使用
- volatile关键字的使用
- volatile关键字的使用
- volatile关键字的使用
- volatile 关键字的使用
- volatile关键字的使用
- 关键字volatile的使用
- Volatile关键字的使用
- volatile 关键字的使用
- volatile关键字的简单介绍
- 使用volatile关键字的原因
- 几个不常使用的java关键字:transient和volatile
- 彻底理解Volatile关键字 &Volatile关键字的使用方式
- java volatile关键字的含义详细介绍
- java Volatile关键字介绍
- java Volatile关键字介绍
- java Volatile关键字介绍
- 二维数组传参
- Wilbur and Swimming Pool(矩形求面积)
- leetcode 8. String to Integer (atoi)
- protobuffer:Please use 'syntax = "proto2";' or 'syntax = "proto3";' to specify a syntax
- VPSMate 不能执行wget命令,不能安装MYSQL问题解决
- volatile关键字的介绍和使用
- JAVA自定义数据结构 更新ing
- 算法 汉诺塔-java详解
- windows下搭建Linux命令、VIM、gcc
- UIView、UIResponder、UIAlertView、UIActionSheet
- 增强版——Firemonkey运行时更改锁定iOS显示方向
- [3201]:Build a Fence
- 第三周上机实践项目——项目1-个人所得税计算器
- dynamic_cast、const_cast、static_cast、reinterpret_cast