java多线程补:充原子性和可见性
参考:http://www.cnblogs.com/mengyan/archive/2012/08/22/2651575.html
原子性:所谓原子性就是不可分割的,比如:在我们编程中直接给变量赋值,这就是不可分割的,就具有原子性,相对的,非原子性就是在编程中步骤被分割的,比如编程中的计算,是分步骤进行的,例如:a+=b,其实编程是分为三步,1、先取出a和b的值 2、计算a+b 3、写入内存。这就是非原子性。
可见性:提到可见性,很多同学就会想到一个关键字 volatile ,没错,在多线程中,解决变量的可见性就是利用了volatile这个修饰词。
多线程变量不可见:当一个线程对一变量a修改后,还没有来得及将修改后的a值回写到主存,而被线程调度器中断操作(或收回时间片),然后让另一线程进行对a变量的访问修改,这时候,后来的线程并不知道a值已经修改过,它使用的仍旧是修改之前的a值,这样修改后的a值就被另一线程覆盖掉了。
多线程变量可见:被volatile修饰的成员变量在每次被线程访问时,都强迫从内存中重读该成员变量的值;而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存,这样在任何时刻两个不同线程总是看到某一成员变量的同一个值,这就是保证了可见性。
举个例子:
编写一个线程类:
public class MyThread4 implements Runnable {
private boolean isRun = true;
public boolean isRun() {
return isRun;
}
public void setRun(boolean run) {
isRun = run;
}
@Override
public void run() {
System.out.println("4开始运行了");
while (isRun){
}
}
}
main()方法运行
MyThread4 myThread4 = new MyThread4();
Thread thread = new Thread(myThread4);
thread.start();
try {
Thread.sleep(100);
myThread4.setRun(false);
System.out.println("停了吗");
} catch (InterruptedException e) {
e.printStackTrace();
}
看运行结果,会发现线程进入了死循环,myThread4.setRun(false);这行代码并没有使线程重新拿到 isRun 的赋值,这说明线程之间对同一个变量的操作是不可见的。
当我们把 isRun 加上volatile关键字时如下:
public class MyThread4 implements Runnable {
private volatile boolean isRun = true;
public boolean isRun() {
return isRun;
}
public void setRun(boolean run) {
isRun = run;
}
@Override
public void run() {
System.out.println("4开始运行了");
while (isRun){
}
}
}
再次运行我们会发现,代码不会进入死循环,由此可见,关键字volatile 保障了线程之间变量的可见性。
拓展:当我们在while循环中加入有synchronized关键字修饰的方法时,比如System.out.println();这时代码也不会陷入死循环,因此synchronized除了保障了原子性外,其实也保障了可见性。因为synchronized无论是同步的方法还是同步的代码块,都会先把主内存的数据拷贝到工作内存中,同步代码块结束,会把工作内存中的数据更新到主内存中,这样主内存中的数据一定是最新的。
java多线程补:充原子性和可见性的更多相关文章
- java多线程3:原子性,可见性,有序性
概念 在了解线程安全问题之前,必须先知道为什么需要并发,并发给我们带来什么问题. 为什么需要并发,多线程? 时代的召唤,为了更充分的利用多核CPU的计算能力,多个线程程序可通过提高处理器的资源利用率来 ...
- java并发特性:原子性、可见性、有序性
要想并发程序正确地执行,必须要保证原子性.可见性以及有序性.只要有一个没有被保证,就有可能会导致程序运行不正确. 1.原子性(Atomicity) 原子性是指在一个操作中就是cpu不可以在中途暂停然后 ...
- 「跬步千里」详解 Java 内存模型与原子性、可见性、有序性
文题 "跬步千里" 主要是为了凸显这篇文章的基础性与重要性(狗头),并发编程这块的知识也确实主要围绕着 JMM 和三大性质来展开. 全文脉络如下: 1)为什么要学习并发编程? 2) ...
- java内存模型的原子性、可见性、有序性与指令重排序
在并发编程中,我们通常会遇到以下三个概念:原子性.可见性和有序性.我们先看具体看一下这三个概念: 1.原子性 操作时不可分割的比如a=0,此操作不可分割,而++a,实际上是a=a+1,为两个操作.想将 ...
- JAVA多线程提高五:原子性操作类的应用
当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量i=1,A线程更新i+1,B线程也更新i+1,经过两个线程操作之后可能i不等于3,而是等于2.因为A和B线程在更新变量i ...
- JAVA多线程学习九-原子性操作类的应用
当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量i=1,A线程更新i+1,B线程也更新i+1,经过两个线程操作之后可能i不等于3,而是等于2.因为A和B线程在更新变量i ...
- Java多线程基础总结
一.线程和进程关系 二.创建方式1.继承Thread类,重写run方法2.实现Runable接口,重写run方法3.使用匿名内部类 三.API接口start()currentThread() 获取当前 ...
- java多线程(4)---volatile关键字
volatile关键字 一旦一个共享变量(类的成员变量.类的静态成员变量)被volatile修饰之后,那么就具备了两层语义: 1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的 ...
- java多线程03-----------------volatile内存语义
java多线程02-----------------volatile内存语义 volatile关键字是java虚拟机提供的最轻量级额的同步机制.由于volatile关键字与java内存模型相关,因此, ...
随机推荐
- Squid 缓存代理服务器的完整配置
Squid 缓存代理服务器 Squid 的作用 1.通过缓存的方式为用户提供web访问加速 2.对用户的web访问进行过滤控制 缓存代理服务器又分为普通代理服务器,透明代理服务器,和反向代理服务器. ...
- Spring 框架的 applicationContext.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- MySQL前后台交互登录系统设计
1.首先我们做一个前台的注册页面 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"& ...
- 初识python(二)
初识python(二) 1.变量 变量:把程序运行的中间结果临时的存在内存里,以便后续的代码调用. 1.1 声明变量: #!/usr/bin/env python # -*- coding: utf- ...
- EasySQLMAIL使用实践系列
原文:http://blog.sina.com.cn/s/articlelist_5713986487_0_1.html 通过sql语句发送微信消息(转) 使用EasySQLMAIL的外部接口功能实现 ...
- 用仿ActionScript的语法来编写html5——第二篇,利用Sprite来实现动画
上一篇,我已经模仿as,加入了LBitmap和LBitmapData类,并且用它们实现了静态图片的显示.这次用Sprite来动态显示图片.依然遵循上一篇对显示对象的处理的思路,添加LSprite类,并 ...
- Apache添加多端口
Apache\conf 目录下 添加端口监听 Vhost.conf简单写写
- LeetCode:全排列II【47】
LeetCode:全排列II[47] 参考自天码营题解:https://www.tianmaying.com/tutorial/LC47 题目描述 给定一个可包含重复数字的序列,返回所有不重复的全排列 ...
- 102. Binary Tree Level Order Traversal ------层序遍历
Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to righ ...
- Calendar的那些神坑
参考我的博客:http://www.isedwardtang.com/2017/08/31/java-calendar-bug/