Java线程volatile(二)
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(二)的更多相关文章
- java线程之二(synchronize和volatile方法)
要说明线程同步问题首先要说明Java线程的两个特性,可见性和有序性.多个线程之间是不能直接传递数据交互的,它们之间的交互只能通过共享变量来实现.拿上篇博文中的例子来说明,在多个线程之间共享了Count ...
- Java线程池二:线程池原理
最近精读Netty源码,读到NioEventLoop部分的时候,发现对Java线程&线程池有些概念还有困惑, 所以深入总结一下 Java线程池一:线程基础 为什么需要使用线程池 Java线程映 ...
- Java线程-volatile不能保证原子性
下面是一共通过volatile实现原子性的例子: 通过建立100个线程,计算number这个变量最后的结果. package com.Sychronized; public class Volatil ...
- java线程(二)
线程范围变量 我们知道线程在cpu上的使用权并不是长时间的,因为计算机的cpu只有一个,而在计算上运行的进程有很多,线程就更不用说了,所以cpu只能通过调度来上多个线程轮流占用cpu资源运行,且为了保 ...
- java 线程 (二) 线程池
package cn.sasa.demo2; import java.util.concurrent.ExecutorService; import java.util.concurrent.Exec ...
- java线程--volatile实现可见性
volatile关键字: 1)能够保证volatile变量的可见性 2)不能保证volatile变量复杂操作的原子性. volatile如何实现内存可见性: 深入来说:通过加入内存屏障和禁止重排序优化 ...
- java线程学习(二)
多个线程并发抢占资源是,就会存在线程并发问题,造成实际资源与预期不符合的情况.这个时候需要设置"资源互斥". 1.创建资源,这个地方我创建了一个资源对象threadResource ...
- Java线程之二 锁定与等待堵塞原理图
如上图所看到的.
- Java线程(二):线程同步synchronized和volatile
上篇通过一个简单的例子说明了线程安全与不安全,在例子中不安全的情况下输出的结果恰好是逐个递增的(其实是巧合,多运行几次,会产生不同的输出结果),为什么会产生这样的结果呢,因为建立的Count对象是线程 ...
随机推荐
- bash循环得到日期目录
#!/bin/bash today=$(date "+%Y%m%d") echo 'today is :'${today} single_input="raw_data/ ...
- 使用localstorage.setItem()存储对象
使用localstorage.setItem(name,value)存储JSON对象时会发现浏览器存储的内容为[object,object],并不是我们想要的内容,这是因为我们在存储的时候没有进行类型 ...
- MintUI引入vue项目以及引入iconfont图标
官网地址:http://mint-ui.github.io/#!/zh-cn 中文文档:http://mint-ui.github.io/docs/#/zh-cn2 示例展示:http://eleme ...
- idea 导入 eclipse java ee 项目,并使用 tomcat 7 部署运行
1.导入java ee项目.直接open 2.导入jar依赖 3.修改编译的目录 4.修改tomcat目录 5.tomcat添加目录 请注意classes单词 D:\project\xxxxxx\We ...
- 缺陷描述(Description)
[tips1] 缺陷报告的用途在于: 记录bug 对bug进行分类(发现者.日期.版本.模块.严重程度.优先级) 跟踪bug(new-open-fixed-closed) 对bug进行统计分析.总结 ...
- 【牛客】小w的魔术扑克 (并查集?? 树状数组)
题目描述 小w喜欢打牌,某天小w与dogenya在一起玩扑克牌,这种扑克牌的面值都在1到n,原本扑克牌只有一面,而小w手中的扑克牌是双面的魔术扑克(正反两面均有数字,可以随时进行切换),小w这个人就准 ...
- 电商ERP系统——商品SKU与库存设计
面试题经常问道,如何设计库存,哪些库存呢?分类属性的库存:不同颜色 不同尺码的属性的库存,这时候需要针对具体的SKU商品创建表. 总体思路 1.商品关联商品类别,商品类别关联多个商品属性,其中指定某几 ...
- sql查询最近7天数据(以年-月-日结果展示)
sql代码如下: , 查询结果如下:
- 从阿里云DATAV GeoAtlas接口抽取行政区划数据
阿里云提供的地理信息接口 https://datav.aliyun.com/tools/atlas/ 有两个接口, 一个是[行政编码].json, 一个是[行政编码]_full.json, 从接口中可 ...
- Java JDBC利用反射技术将查询结果封装为对象
1.JDBC将返回结果集封装成对象demo class JdbcDemo { /** * 获取数据库列名 * @param rs * @return */ private static String[ ...