15_volatile
【volatile概念】
volatile关键字的主要作用是是变量在多个线程间可见。
【注意】
在java中,每一个线程都会有一块工作内存区,其中存放着所有线程共享的主内存中的变量的拷贝。当线程执行时,他在自己的工作内存区中操作这些变量。为了存取一个共享的变量,一个线程通常会先获取并去清除它的内存工作区,把这些共享变量从所有线程的共享内存区中正确地装入到他自己所在的工作内存区中,当线程解锁时保证该内存区中变量的值写回到共享内存中。
一个线程可以执行的操作有:使用(use)、赋值(assign)、装载(load)、存储(store)、锁定(lock)、解锁(unlock)。
而主内存可以执行的操作有:读(read)、写(write)、锁定(lock)、解锁(unlock),每个操作都是原子的。
volatile的作用就是强制线程到主内存(共享内存)里去读取变量,而不去线程工作内存区里去读取,从而实现了多个线程间的变量可见。也就是满足线程安全的可见性。
【线程执行流程图】

【volatile可见性的例子】
package com.higgin.part6;
public class MyThread extends Thread{
/**
* 加与不加volatile
* 不加volatile:main线程中将isRunning设置为flase,MyThread线程中的isRunning不会改变
* 加上volatile:main线程中将isRunning设置为flase,MyThread线程中的isRunning会随之改变
*/
private volatile boolean isRunning = true;
private void setRunning(boolean isRunning){
this.isRunning = isRunning;
}
@Override
public void run(){
System.out.println("进入run()方法...");
while(isRunning){
//如果MyThread线程的isRunning不改为false,线程会永远卡在这里
}
System.out.println("线程停止!!!");
}
public static void main(String[] args) throws InterruptedException {
MyThread mt = new MyThread();
mt.start();
Thread.sleep();
mt.setRunning(false);
System.out.println("isRunning的值已经设置为false...");
}
}
【运行结果:不加volatile,MyThread线程一直没有结束】

【运行结果:加上volatile,Main线程改变了isRunning,MyThread线程中的isRunning随之改变,MyThread线程可以停止】

【volatile只有可见性,没有原子性的验证例子】
package com.higgin.part6; import java.util.concurrent.atomic.AtomicInteger; /**
* volatile关键字具备可见性,但不具备synchronized关键字的原子性(同步)
*/
public class VolatileThread extends Thread{ /**
* 使用volatile int 和 AtomicInteger的区别
* 使用volatile int :只有可见性,没有原子性
* 使用 AtomicInteger:原子性,确保最终的结果必为50000
*/
private static volatile int count;
// private static AtomicInteger count = new AtomicInteger(0); //初始化为0 private static void addCount(){
for(int i=; i<; i++){
count++;
// count.incrementAndGet();
}
System.out.println("count="+count); //for循环结束后,打印count的值
} @Override
public void run(){
addCount();
} public static void main(String[] args) {
VolatileThread[] threads = new VolatileThread[]; //100个线程 for(int i=; i<; i++){
threads[i] = new VolatileThread(); //为数组中的每个元素初始化对象
} for(int i=; i<; i++){
threads[i].start();
}
} }
【运行结果,使用volatile,多运行几遍会出现错误】

【运行结果:使用AtomicInteger】

【运行结果:使用AtomicInteger,虽然中间有可能会出现数据错乱的问题,但最终结果必定为50000】

【多个addAndGet在一个方法内是非原子性的,需要加synchronized修饰,保证4个addAndGet的原子性】
package com.higgin.part6; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; public class AtomicDemo {
private static AtomicInteger count = new AtomicInteger(); /**
* 加和不加synchronized
* 多个addAndGet在一个方法内是非原子性的,需要加synchronized修饰,保证4个addAndGet的原子性
*/
public synchronized int multiAdd(){
count.addAndGet();
count.addAndGet();
count.addAndGet();
count.addAndGet(); //count=count+1+2+3+4=count+10;
return count.get(); //返回count的值
} public static void main(String[] args) {
final AtomicDemo ad = new AtomicDemo(); List<Thread> tList = new ArrayList<Thread>(); for(int i=; i<; i++){
tList.add(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("count=="+ad.multiAdd());
}
}));
} for(Thread t : tList){
t.start();
}
}
}
【运行结果:不加synchronized,虽然可以确保最后一次结果为1000,但是中途有可能不是10的倍数】

【运行结果:加上synchronized修饰】

15_volatile的更多相关文章
随机推荐
- layer mobile开发layer.full
Layer For Mobile 之 layer.full() 背景介绍:layer mobile是专门针对手机页面开发的一套框架,具体介绍请看官方文档 http://layer.layui.com/ ...
- 搭建svn管理平台
安装svn服务器:yum -y install subversion 创建svn的目录:mkdir -p /data/svn 初始化svn目录:svnadmin create /data/svn co ...
- vue的props和$emit / 父子组件通信
props 父级: 父级组件中引用子组件,并将自己data下面的giveChild数据绑定在 giveChildData 传给子 <myChild :giveChildData=" ...
- Win10如何新建用户怎么添加新账户
https://jingyan.baidu.com/article/25648fc162d5899190fd0069.html 很多朋友都是安装完Windows10系统后,直接使用超级管理员账号登录系 ...
- properties 资源文件读取
1. 在source中添加资源文件 resource.properties #FTP 相关配置 #FTP 的ip地址 FTP_ADDRESS=192.168.88.142 FTP_PORT=21 ...
- m3m4加载器的优化版m3m4-v1.1
m3m4加载器的优化版m3m4-v1.1 /* //1.以$开头的模块名,表示服务,服务只会执行一次,它可以有自己的方法.比如cookie就是一个服务 //例如:console.log("r ...
- cmd命令行编译c/c++程序
一.打开文件夹(文件夹名字为123,文件夹里面有程序345.cpp) cd 123 二.在cmd里面编译程序 1.cd Desktop //在打开文件夹之前不回到桌面会出错 2.cd 123 ...
- Python爬虫常用之PyQuery
PyQuery是解析页面常用的库.是python对jquery的封装.下面是一份解析基本页面的代码.后期用到复杂或者实用的方式再增加. from pyquery import PyQuery as p ...
- Python基础 (上)
参考:菜鸟教程 Python用途 目录 一.数据类型 二.运算符 三.条件和循环控制语句 四.函数 五.模块 六.输入与输出 一.数据类型 string.list和tuple都属于sequenc ...
- python学习8-闭包、迭代器(转载)
一.第一类对象: 函数名是一个变量,可以当普通变量使用,但它又是一个特殊的变量,与括号配合可以执行函数. 函数名的运用 1.单独打印是一个内存地址 2.可以给其他变量赋值 3.可以作为容器类变量的元素 ...