【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. JUnit4.13环境配置

    Junit 4.13环境配置 JUnit是一个强大的单元测试工具.它可以针对某一个特定类的所有方法进行精确打击.这个东西具体怎么使用,留在以后说.这次给大家说说idea下配置JUnit环境的方法. 1 ...

  2. ORA-28009: 应当以 SYSDBA 身份或 SYSOPER 身份建立 SYS 连接

    用 SQL*Plus 连接数据库的时候,除了用户名和密码外,还要在口令后面加一个主机字符串.如下: 请输入用户名:sys 口令:ANKoracle123,orcl as sysdba

  3. POJ_3126 Prime Path 【BFS+素数打表】

    一.题目 http://poj.org/problem?id=3126 二.分析 该题主要是要让我们找到一个$4$位素数到另一个$4$位素数的最少的变换次数,且要求保证每一次变换都满足 1.下一个数必 ...

  4. 马的移动(BFS) 详细注释 一个具有情怀的题目

    题目描述 小明很喜欢下国际象棋,一天,他拿着国际象棋中的"马"时突然想到一个问题: 给定两个棋盘上的方格a和b,马从a跳到b最少需要多少步? 现请你编程解决这个问题. 提示:国际象 ...

  5. 4.整体架构和Smart Scan

    寻道时间: 外圈,比内圈要多, 即外圈是比较快的. 第一次创建grid disk 时,是创建外圈,用于存放数据的,内圈存储归档这些数据 CellCLI> CREATE GRIDDISK ALL ...

  6. 3.Exadata 软件体系结构

    整体架构和 smart scan Aasm Ehcc (混合例压缩 和 存储索引) SCAN Service 和 server pool DB SERVER -> DB instance -&g ...

  7. http请求报头和响应报头(1)

    1.web端不可避免的http缓存机制,要理解缓存机制,先来了解下http的请求报文和响应报文的内容 2.请求报文  2.1请求行    请求行三部分组成:请求方法.URL以及版本协议 请求的方法有G ...

  8. quartz使用(整合spring)

    quartz与spring整合后,还是需要Scheduler实例.JobDetail实例.Trigger实例,只不过是用FactoryBean的方式创建了. 在spring-context-suppo ...

  9. mysql记录数据库中重复的字段的数据

    SELECT    SUM(co)FROM    (        SELECT            telephone,            count(telephone) AS co     ...

  10. GreenPlum 大数据平台--运维(一)

    .最后分析或真空或创建表或等... Select * from pg_stat_operations where schemaname='SCHEMA NAME ' and actionname in ...