【Java 并发编程】线程简介 ( 原子操作 | volatile 关键字使用场景 )
文章目录
一、原子操作
原子操作 :
read : 从 主内存 中的线程共享变量中读取数据 ; load : 将从主内存读取到的数据 , 加载到 线程工作内存 中 ;
read 和 load 操作一定是 成对出现 的 , 只要从主内存中读取到数据 , 一定会将这个数据加载到线程的工作内存中 ;
use : 从线程共享变量副本读取到线程的 执行引擎 中 ; assign : 从执行引擎中写出数据到变量的 共享变量副本 中 ;
store : 将数据从线程工作内存传输到 主内存 中 ; write : 将数据赋值给主内容中的线程 共享变量 ;
lock : 作用于 主内存中的线程共享变量 , 将该变量标识为 被某个线程独自占用状态 ; 表示该变量只有一个线程可以进行访问 ; unlock : 解锁 主内存中的共享变量 , 其它线程可以进行访问 ;
二、volatile 关键字使用场景
在下面的示例中 , 设置一个标志位 , 主线程开始后 , 启动一个线程 , 休眠
毫秒 , 然后修改该标志位 , 主线程中根据标志位进行循环 , 如果标志位被修改 , 则循环停止 , 但是循环一直没有停止 ;
也就是说线程中修改的值 , 仅修改了该线程中工作内存中的标志位副本的值 ;
主内存中的值没有被修改 ;
代码示例 :
public class Main {
private static boolean flag = false;
private static void changeFlag() {
System.out.println("修改标志位开始");
flag = true;
System.out.println("修改标志位结束");
}
public static void main(String[] args) {
// 在该线程中 , 1 秒后修改标志位为 false
new Thread(){
@Override
public void run() {
super.run();
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
changeFlag();
}
}.start();
// 此处如果 flag 一直为 flase 就会进入死循环
// 如果 flag 为 true 则程序结束
while (!flag) {
}
System.out.println("主线程结束");
}
}
执行结果 :
原理分析 :
线程的工作内存中 , 将 flag
修改为 true
, 这只是在 CPU 缓存 中修改的 , 没有在主内存中修改这个共享变量值 , 因此主线程访问该值 , 还是 false
;
使用 volatile 关键字 , 禁用 CPU 的缓存 , 直接在主内存中进行读写 , 这样就可以解决多个线程中 共享变量 不同步的问题 ;
注意 : 只能是 线程共享变量 使用该关键字 , 设置该关键字会影响线程的执行效率 , 效率会降低 ;
使用了 volatile 关键字后的效果 :
public class Main {
private static volatile boolean flag = false;
private static void changeFlag() {
System.out.println("修改标志位开始");
flag = true;
System.out.println("修改标志位结束");
}
public static void main(String[] args) {
// 在该线程中 , 1 秒后修改标志位为 false
new Thread(){
@Override
public void run() {
super.run();
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
changeFlag();
}
}.start();
// 此处如果 flag 一直为 flase 就会进入死循环
// 如果 flag 为 true 则程序结束
while (!flag) {
}
System.out.println("主线程结束");
}
}
执行结果 :
Java 并发的
特性 :
- 原子性 : 每个操作都是 不可拆分的原子操作 ; 在线程中进行
a++
就不是原子操作 , 该操作分为
个步骤 , 首先从主内存中读取 a
变量 , 然后进行自增操作 , 最后在将自增后的值写回主内存中 ;
- 可见性 : 多个线程 访问同一个变量 , 该变量一旦被 某个线程修改 , 这些线程必须可以 立刻看到被修改的值 ;
- 有序性 : 程序按照 代码先后顺序 执行 ;
volatile 关键字 , 禁用了 CPU 缓存 , 解决的是共享变量可见性问题 ;
相关文章
- 女生学java_Java Server Pages
- java volatile关键字的作用_Java并发编程彻底搞懂volatile关键字「建议收藏」
- java笔试题_一道简单的 Java 笔试题,但值得很多人反思
- java标识符与关键字_4、Java标识符和关键字
- java多线程面试题大全_java多线程面试题_线程并发面试题
- MySQL字段类型如何转为java_Java JDBC中,MySQL字段类型到JAVA类型的转换
- 【说站】java中并发和并行的概念
- 【JAVA面试必会】JMM高并发详解(java内存模型、JMM三大特征、volatile关键字 )「建议收藏」
- 一文带你深入理解Java多线程与高并发:Atomic类和线程同步新机制
- java list 转json 字符串_Java之JSON字符串与List集合之间相互转换
- java事务_Java 事务详解[通俗易懂]
- java 舆情分析_基于Java实现网络舆情分析系统研究与实现.doc[通俗易懂]
- Java map转实体类_java实体类转json
- 并发多线程学习(六)Java线程间的通信
- c 线程安全的单例模式-c多线程并发处理方式_Java多线程面试题:线程锁+线程池+线程同步等
- 虚拟线程将会深刻影响大规模Java应用的并发机制
- 【Java 集合】Java 集合的线程安全性 ( 加锁同步 | java.utils 集合 | 集合属性 | java.util.concurrent 集合 | CopyOnWrite 机制 )
- 【Java 并发编程】线程简介 ( 进程与线程 | 并发概念 | 线程间通信 | Java 并发 3 特性 )
- 【Java 并发编程】线程池机制 ( 测试线程开销 | 启动线程分析 | 用户态 | 内核态 | 用户线程 | 内核线程 | 轻量级进程 )
- 【Java 并发编程】线程池机制 ( 线程池示例 | newCachedThreadPool | newFixedThreadPool | newSingleThreadExecutor )
- 【Java 并发编程】线程池机制 ( 线程池状态分析 | 线程池状态转换 | RUNNING | SHUTDOWN | STOP | TIDYING | TERMINATED )
- java线程池和并发集合(二)
- Java面试:15个多线程和并发面试题详解编程语言
- Java线程新特征——Java并发库详解编程语言
- Java连接MySQL数据库的简单步骤(java如何连接mysql数据库)
- Java高效操作MySQL数据库(java写入mysql)
- 构建Java应用程序中Redis集群的方法(java连redis集群)
- 实现高并发:Java利用Redis秒杀成功(java秒杀redis)
- java使用Weka、Linux和Java构建强大的数据分析系统(weka linux)
- Linux下开发靠谱的Java应用(linux基于java)
- 项目Java项目中展现Redis新型性能优势(redis运用在java)
- java线程并发countdownlatch类使用示例
- java线程并发blockingqueue类使用示例
- Java并发编程示例(八):处理线程的非受检异常