volatile:使变量在多个线程中可见

在java 中每个线程都会有一块工作内存区,其中存放着所有线程共享的主内存中变量的拷贝。当线程执行时,在自己的工作内存区操作这些变量,为了存取一个共享的变量,

一个线程通常先获取锁定并去清除它的内存工作区,把这些共享变量从所有线程的共享内存中正确的装入到他自己所在的工作内存区中,

当线程解锁时,保证该工作内存中变量的值写回到共享内存中。

一个线程可以执行的操作有使用(use)、赋值(assign)、装载 (load)、存储(store)  锁定(lock)  解锁(unloack)

主内存可以执行的操作有读(read) 写(write) 锁定(lock) 解锁(unlock) 每个操作都是原子的

public class RunThread extends Thread{

	private volatile boolean isRunning = true;
private void setRunning(boolean isRunning){
this.isRunning = isRunning;
} public void run(){
System.out.println("进入run方法..");
int i = 0;
while(isRunning == true){
//..
}
System.out.println("线程停止");
} public static void main(String[] args) throws InterruptedException {
RunThread rt = new RunThread();
rt.start();
Thread.sleep(1000);
rt.setRunning(false);
System.out.println("isRunning的值已经被设置了false");
}
}

  

  

volatile关键字虽然拥有多个线程之间的可见性,但不具备同步性,算一个轻量级的synchronized,性能要比synchronized强很多,不会造成阻塞。

一般用于针对多个线程可见的变量操作,并不能代替synchronized的同步功能。

volatile关键字只有可见性,没有原子性,要实现原子性使用atomic类的系列对象,支持原子性操作,atomic类只保证方法原子性,并不保证多次操作的原子性

public class VolatileNoAtomic extends Thread{
//private static volatile int count;
private static AtomicInteger count = new AtomicInteger(0); //具有原子操作的特性
private static void addCount(){
for (int i = 0; i < 1000; i++) {
//count++ ;
count.incrementAndGet();
}
System.out.println(count);
} public void run(){
addCount();
} public static void main(String[] args) { VolatileNoAtomic[] arr = new VolatileNoAtomic[100];
for (int i = 0; i < 10; i++) {
arr[i] = new VolatileNoAtomic();
} for (int i = 0; i < 10; i++) {
arr[i].start();
}
}
}

  

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; public class AtomicUse { private static AtomicInteger count = new AtomicInteger(0); //多个addAndGet在一个方法内是非原子性的,需要加synchronized进行修饰,保证4个addAndGet整体原子性
/**synchronized*/
public synchronized int multiAdd(){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
count.addAndGet(1);
count.addAndGet(2);
count.addAndGet(3);
count.addAndGet(4); //+10
return count.get();
} public static void main(String[] args) { final AtomicUse au = new AtomicUse(); List<Thread> ts = new ArrayList<Thread>();
for (int i = 0; i < 100; i++) {
ts.add(new Thread(new Runnable() {
@Override
public void run() {
System.out.println(au.multiAdd());
}
}));
} for(Thread t : ts){
t.start();
}
}
}

  

 

Volatile称之为轻量级锁,被volatile修饰的变量,在线程之间是可见的,保证不了操作的原子性

可见:一个线程修改了这个变量的值,在另一个线程中能够读取到这个修改的值

Synchronized:除了线程之间的互斥意外,还有一个非常的大的作用,就是保证可见性 

//保证可见性的前提
//多个线程拿到的是同一把锁,否则是保证不了的
public class Demo { public volatile int a=1;
public static void main(String[] args) {
Demo demo=new Demo();
demo.a=10;
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(demo.a);
}
}).start(); System.out.println("最终的结果为:"+demo.a);
} }

  

public class Demo2 {
public volatile boolean run =false;
public static void main(String[] args) {
Demo2 d=new Demo2();
new Thread(new Runnable() {
@Override
public void run() {
for(int i=1;i<=10;i++){
System.out.println("执行了第"+i+"次");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
d.run=true;
}
}).start(); new Thread(new Runnable() { @Override
public void run() {
while(!d.run){
//不执行
}
System.err.println("线程2执行了");
}
}).start();
}
}

  lock指令:

在多处理器的系统上

将当前处理器缓存行的内容写回到系统内存,

写回到内存操作会使在其他CPU里缓存了该内存地址的数据失效

Java线程volatile(二)的更多相关文章

  1. java线程之二(synchronize和volatile方法)

    要说明线程同步问题首先要说明Java线程的两个特性,可见性和有序性.多个线程之间是不能直接传递数据交互的,它们之间的交互只能通过共享变量来实现.拿上篇博文中的例子来说明,在多个线程之间共享了Count ...

  2. Java线程池二:线程池原理

    最近精读Netty源码,读到NioEventLoop部分的时候,发现对Java线程&线程池有些概念还有困惑, 所以深入总结一下 Java线程池一:线程基础 为什么需要使用线程池 Java线程映 ...

  3. Java线程-volatile不能保证原子性

    下面是一共通过volatile实现原子性的例子: 通过建立100个线程,计算number这个变量最后的结果. package com.Sychronized; public class Volatil ...

  4. java线程(二)

    线程范围变量 我们知道线程在cpu上的使用权并不是长时间的,因为计算机的cpu只有一个,而在计算上运行的进程有很多,线程就更不用说了,所以cpu只能通过调度来上多个线程轮流占用cpu资源运行,且为了保 ...

  5. java 线程 (二) 线程池

    package cn.sasa.demo2; import java.util.concurrent.ExecutorService; import java.util.concurrent.Exec ...

  6. java线程--volatile实现可见性

    volatile关键字: 1)能够保证volatile变量的可见性 2)不能保证volatile变量复杂操作的原子性. volatile如何实现内存可见性: 深入来说:通过加入内存屏障和禁止重排序优化 ...

  7. java线程学习(二)

    多个线程并发抢占资源是,就会存在线程并发问题,造成实际资源与预期不符合的情况.这个时候需要设置"资源互斥". 1.创建资源,这个地方我创建了一个资源对象threadResource ...

  8. Java线程之二 锁定与等待堵塞原理图

    如上图所看到的.

  9. Java线程(二):线程同步synchronized和volatile

    上篇通过一个简单的例子说明了线程安全与不安全,在例子中不安全的情况下输出的结果恰好是逐个递增的(其实是巧合,多运行几次,会产生不同的输出结果),为什么会产生这样的结果呢,因为建立的Count对象是线程 ...

随机推荐

  1. 洛谷P4408 逃学的小孩

    题目 求树的直径,因为任意两个居住点之间有且只有一条通路,所以这是一棵树. 根据题意父母先从C去A,再去B,或者反过来. 我们一定是要让A到B最大,也要让C到A和B的最小值最大. AB最大一定就是直径 ...

  2. 什么是 FOUC(无样式内容闪烁)?你如何来避免 FOUC?

    css引入了@import 或者存在多个style标签以及css文件在页面底部 使得css文件加载在html之后导致页面闪烁.花屏 用link加载css文件,放在head标签里面

  3. Android入门教程(三)

    对Android五大布局的描述,分别是 FrameLayout (框架布局),LinearLayout (线性布局),AbsoluteLayout (绝对布局),RelativeLayout (相对布 ...

  4. C语言博客作业--结构体,文件

    1.本章学习总结(2分) 1.1 学习内容总结 (1)结构体如何定义.成员如何赋值 结构体的一般形式为:      struct  结构体名     {      数据类型 成员名1:      数据 ...

  5. Painting The Fence(贪心+优先队列)

    Painting The Fence(贪心+优先队列) 题目大意:给 m 种数字,一共 n 个,从前往后填,相同的数字最多 k 个在一起,输出构造方案,没有则输出"-1". 解题思 ...

  6. PHP strtok() 函数

    我们仅在第一次调用 strtok() 函数时使用了 string 参数.在首次调用后,该函数仅需要 split 参数,这是因为它清楚自己在当前字符串中所在的位置. 如需分割一个新的字符串,请再次调用带 ...

  7. element ui 合计/table show-summary

    在el-table 上面加上show-summary就可以对table的数据进行合计 但是上次出现了合计栏有的为空,有的合计不对的情况,如果出现的是空,那么说明你渲染的数据有undefine(即后台返 ...

  8. avalon用background-image不起作用,怎么来选取前几个的图片进行渲染

    <span ms-css="{backgroundImage: 'url('+item.image + ')'}" ms-for="($index,item) in ...

  9. Linux 文件压缩、打包

    文件压缩 计算机使用byte单位来计量.实际上,计算机最小的计量单位是bit.1byte = 8 bit.如果记录1这个数字,00000001,1会在最右边占一个1个bit 其他7个bit会被填上0. ...

  10. 第06组 Alpha事后诸葛亮

    一.组长博客: https://www.cnblogs.com/mhq-mhq/p/11923194.html 二.Postmortem模板 设想和目标 1.我们的软件要解决什么问题?是否定义得很清楚 ...