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. LOJ572. 「LibreOJ Round #11」Misaka Network 与求和 [莫比乌斯反演,杜教筛,min_25筛]

    传送门 思路 (以下令\(F(n)=f(n)^k\)) 首先肯定要莫比乌斯反演,那么可以推出: \[ ans=\sum_{T=1}^n \lfloor\frac n T\rfloor^2\sum_{d ...

  2. 「ZJOI2016」小星星

    传送门 Description Solution 容斥,考虑有多少个节点不被匹配到,求出的方案,多个点可以同时不被匹配到 状态压缩+树形dp Code  #include<bits/stdc++ ...

  3. Swarm容器集群管理(超详细)

    一.Swarm介绍 Swarm是Docker公司自研发的容器集群管理系统, Swarm在早期是作为一个独立服务存在, 在Docker Engine v1.12中集成了Swarm的集群管理和编排功能.可 ...

  4. Java URLDecoder和URLEncoder对中文进行编码和解码

    URLDecoder类包含一个decode(String s,String enc)静态方法,它可以将application/x-www-form-urlencoded MIME字符串转成普通字符串: ...

  5. Neural Architecture Search — Limitations and Extensions

    Neural Architecture Search — Limitations and Extensions 2019-09-16 07:46:09 This blog is from: https ...

  6. Proxy Server源码及分析(TCP Proxy源码 Socket实现端口映射)

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/u014530704/article/de ...

  7. oracle/mysql java jdbc类型映射

    MySQL数据类型 JAVA数据类型 JDBC TYPE 普通变量类型 主键类型 BIGINT Long BIGINT 支持 支持 TINYINT Byte TINYINT 支持 不支持 SMALLI ...

  8. P1981 表达式求值

    P1981 表达式求值 题解 这个题联想一下  P1310 表达式的值  思路就是输入中缀式,转成后缀式,然后按后缀式计算,完美!!       but!! 会严重RE,因为你可能会输入中缀式的时候输 ...

  9. Innodb的redo log block

  10. python 上下文管理器contextlib.ContextManager

    1 模块简介 在数年前,Python 2.5 加入了一个非常特殊的关键字,就是with.with语句允许开发者创建上下文管理器.什么是上下文管理器?上下文管理器就是允许你可以自动地开始和结束一些事情. ...