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对象是线程 ...
随机推荐
- 可分离卷积详解及计算量 Basic Introduction to Separable Convolutions
任何看过MobileNet架构的人都会遇到可分离卷积(separable convolutions)这个概念.但什么是“可分离卷积”,它与标准的卷积又有什么区别?可分离卷积主要有两种类型: 空间可分离 ...
- Prometheus监控神技--自动发现配置
一.自动发现类型 在上一篇文中留了一个坑: 监控某个statefulset服务的时候,我在service文件中定义了个EP,然后把pod的ip写死在配置文件中,这样,当pod重启后,IP地址变化,就监 ...
- SSM项目的搭建
本文示例在如下环境下搭建一个Maven+Druid+SSM+Shiro+Mysql+PageHelper以及Mybatis Generator反向生成代码的项目 附上GitHub地址:https:// ...
- Java_jdbc 基础笔记之九 数据库连接 (查询Customer对象的方法)
/** * * 写一个查询Customer对象的方法 * */ public Customer getCustomer(String sql, Object... args) { Customer c ...
- 论文解读:3D Hand Shape and Pose Estimation from a Singl RGB Image
本文链接:https://blog.csdn.net/williamyi96/article/details/89207640由于最近做到了一些 3D Hand Pose Estimation 相关的 ...
- jq select change下拉框选项变化判断选中值,添加(attr)或移除(removeAttr)一个或多个属性
select change下拉框选项变化判断选中值,添加(attr)或移除(removeAttr)一个或多个属性 $("#IsRecommend").change(function ...
- (2)PyCharm开发Flash项目之蓝图构建
下面通过在PyCharm开发工具中创建一个简单的Flask项目来体会一下Flask的蓝图构建(Blueprint). 何谓蓝图:在Flask中蓝图就在大型应用中,将不同功能的模块(module)分开管 ...
- C语言 字符串切割
#include <stdio.h> #include <stdlib.h> #include <string.h> /* 字符串切割函数 */ /* 知识补充: ...
- LODOP中无规律无法还原偶尔出现问题排查
一些问题无法还原且偶尔出现,没法通过做例子来展示问题,为了找到问题在哪里,就需要排查定位问题 .由于这些问题偶尔出现,且无规律,出现频率低,所以只能不断通过各种对比测试,定位排查到问题和什么有关.如果 ...
- Eclipse安装Properties Editor插件
安装步骤 1.打开eclispe编辑器help-->install new soft 2.输入软件地址 name:properties editor Location:http://proped ...