【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的更多相关文章

随机推荐

  1. 查看SELinux状态及关闭SELinux

    查看SELinux状态: 输入:/usr/sbin/sestatus -v SELinux status: enabled           ##开启状态 关闭SELinux 修改vi /etc/s ...

  2. Linux 查看文件夹命令

    1,按照时间升序 命令:ls -lrt 详细解释:        -l use a long listing format 以长列表方式显示(详细信息方式)       -t sort by modi ...

  3. JavaWeb学习笔记(十)—— JavaBean总结【转】

    一.什么是JavaBean JavaBean是一个遵循特定写法的Java类,它通常具有如下特点: 这个Java类必须具有一个无参的构造函数 属性必须私有化. 私有化的属性必须通过public类型的方法 ...

  4. 【算法笔记】B1003 我要通过!

    1003 我要通过! (20 分) “答案正确”是自动判题系统给出的最令人欢喜的回复.本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”,否则输出“答案 ...

  5. plsql11破解注册码

    plsql11.0.6.1796-64bit的可以用注册码: Product Code:4t46t6vydkvsxekkvf3fjnpzy5wbuhphqz serial Number: passwo ...

  6. 离散化test

    #include<bits/stdc++.h> using namespace std; const int maxn = 1e6+11; int ll[maxn],rr[maxn],ma ...

  7. springboot(六)-使用shiro

    前提 写之前纠结了一番,这一节放在shiro里面还是springboot里面.后来想了下,还是放springboot里吧,因为这里没有shiro的新东西,只有springboot添加了新东西的使用. ...

  8. day_01 python基础 基本数据类型 if条件

    1. python简介 解释型,弱类型,高级开发语言2. 第一个python程序编写   1. 标点符号(英文)   2. 编码格式(utf-8)3.变量   把程序运行产生的中间值储存起来,方便后面 ...

  9. 【总结】sqlmap命令

    post -u url --forms --skip(指定跳过参数) "" --technique BEUST(自选) --dbms mysql --batch --threads ...

  10. Linux-密码复杂度限制

    前言 设置一个复杂的密码,可以有效的提升系统的安全性.在Linux上有PAM(Pluggable Authentication Modules)里面有一个pam_cracklib.so来控制密码的复杂 ...