(Java多线程系列七)Java内存模型和线程的三大特性
Java内存模型和线程的三大特性
多线程有三大特性:原子性、可见性、有序性
1、Java内存模型
Java内存模型(Java Memory Model ,JMM),决定一个线程对共享变量的写入时,能对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。
用一张图表示Java内存模型
2、原子性
原子性即一个操作或多个操作,要么全部执行并且执行过程不被任何因素打断,要么就都不执行。
一个经典的例子就是数据库存储的事务。原子性其实就是保证数据一致、线程安全的一部分。
Synchronized、lock可以解决线程原子性问题
3、可见性
当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
若两个线程在不同的cpu,那么线程1改变了i的值还没刷新到主存,线程2又使用了i,那么这个i值肯定还是之前的,线程1对变量的修改其他线程没看到,这就是可见性问题。
Volatile可以解决线程可见性问题
4、有序性
程序执行的顺序按照代码的先后顺序执行。
一般来说处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。
而在多线程就不一定了,所以我们在多线程编程时就得考虑这个问题了。
5、volatile关键字可以解决线程之间可见性的问题
class ThreadDemo extends Thread {
boolean flag;
ThreadDemo(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
System.out.println(getName() + "线程开始运行。。。");
while (flag) {
}
System.out.println(getName() + "线程已经结束。。。");
}
public void stopThread() {
this.flag = false;
}
}
public class VolatileThreadDemo {
public static void main(String[] args) {
ThreadDemo threadDemo = new ThreadDemo(true);
threadDemo.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
threadDemo.stopThread();
}
}
先来看以上的代码,在主线程中调用
threadDemo.stopThread()
方法停止线程,看上去逻辑没有问题,但是我们会发现线程没有停止。
注意:有的同学可能在测试上面代码的时候程序可以正常退出。那是因为你的JVM没有优化造成的!
造成线程没有停止的原因是
while(flag)
中的flag是在线程运行的“工作内存”中获取的,而不是从“主内存”中获取的,这就造成了我们在主线程中改变flag的值对于子线程中不生效。只要在flag前加volatile关键字,强制线程每次读取该值的时候都去“主内存”中取值,就能解决我们的问题。
package com.littlestones.volatiledemo;
/**
* @program: JavaThreadLearn
* @description: volatile示例
* @author: Leil
* @create: 2019-12-24 15:22
*/
class ThreadDemo extends Thread {
volatile boolean flag;
ThreadDemo(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
System.out.println(getName() + "线程开始运行。。。");
while (flag) {
}
System.out.println(getName() + "线程已经结束。。。");
}
public void stopThread() {
this.flag = false;
}
}
public class VolatileThreadDemo {
public static void main(String[] args) {
ThreadDemo threadDemo = new ThreadDemo(true);
threadDemo.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
threadDemo.stopThread();
}
}
注意:volatile关键字只能解决线程的可见性问题,不能解决线程的原子性问题
(Java多线程系列七)Java内存模型和线程的三大特性的更多相关文章
- java多线程系列(七)---Callable、Future和FutureTask
Callable.Future和FutureTask 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量 ...
- 深入理解Java虚拟机读书笔记8----Java内存模型与线程
八 Java内存模型与线程 1 Java内存模型 ---主要目标:定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节. ---此处的变量和J ...
- 【java多线程系列】java内存模型与指令重排序
在多线程编程中,需要处理两个最核心的问题,线程之间如何通信及线程之间如何同步,线程之间通信指的是线程之间通过何种机制交换信息,同步指的是如何控制不同线程之间操作发生的相对顺序.很多读者可能会说这还不简 ...
- 【java多线程系列】java中的volatile的内存语义
在java的多线程编程中,synchronized和volatile都扮演着重要的 角色,volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的可见性,可见性指的是当一 ...
- Java多线程系列七——ExecutorService
java.util.concurrent.ExecutorService接口提供了许多线程管理的方法 Method 说明 shutdown 拒绝接收新的任务,待已提交的任务执行后关闭,且宿主线程不阻塞 ...
- 【Java多线程系列七】ExecutorService
java.util.concurrent.ExecutorService接口提供了许多线程管理的方法 Method 说明 shutdown 拒绝接收新的任务,待已提交的任务执行后关闭,且宿主线程不阻塞 ...
- 深入理解java虚拟机(6)---内存模型与线程 & Volatile
其实关于线程的使用,之前已经写过博客讲解过这部分的内容: http://www.cnblogs.com/deman/category/621531.html JVM里面关于多线程的部分,主要是多线程是 ...
- Java多线程系列一——Java实现线程方法
Java实现线程的两种方法 继承Thread类 实现Runnable接口 它们之间的区别如下: 1)Java的类为单继承,但可以实现多个接口,因此Runnable可能在某些场景比Thread更适用2) ...
- java多线程系列(八)---CountDownLatch和CyclicBarrie
CountDownLatch 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 java多线 ...
随机推荐
- appium常见问题03_appium脚本报错selenium.common.exceptions.WebDriverException
运行appium脚本时报错selenium.common.exceptions.WebDriverException...,如下截图: 该报错说明appium和app的内置chrome版本不一致 [解 ...
- Selenium:下拉框处理(Select模块)
在UI自动化测试过程中,经常会遇到一些下拉框,如果我们基于Webdriver操作的话就需要click两次,而且很容易出现问题,实际上Selenium给我们提供了专门的Select(下拉框处理模块). ...
- 兼容ie浏览器的方法
让IE6 IE7 IE8 IE9 IE10 IE11支持Bootstrap的解决方法 最近做一个Web网站,之前一直觉得bootstrap非常好,这次使用了bootstrap3,在chrome,f ...
- 10分钟掌握Python-机器学习小项目
学习机器学习相关技术的最好方式就是先自己设计和完成一些小项目. Python 是一种非常流行和强大的解释性编程语言.不像 R 语言,Python 是个很完整的语言和平台,你既可以用来做研发,也可以用来 ...
- Linux Kernel中所應用的數據結構及演算法
Linux Kernel中所應用的數據結構及演算法 Basic Data Structures and Algorithms in the Linux kernel Links are to the ...
- 【知识强化】第四章 网络层 4.7 IP组播
这节课我们来学习一下IP组播. 首先我们来看这样一个问题,IP数据报在网络当中传输的时候,有几种传输方式呢?三种,分别是单播.广播和组播(多播).这个组播呢也叫做多播,它们俩是一个意思.那这个组播是由 ...
- shell使用reposync同步仓库
- USB hub串口绑定
方式一 1.查看串口信息 udevadm info /dev/ttyUSB0 2.创建配置文件 sudo vi /etc/udev/rules.d/com_port.rules ACTION==&qu ...
- Oracle之子查询:Top-N问题
学习了SQL子查询,遇到个Top-N问题,即:加入有张工资表(这里使用Oracle SCOTT用户的emp表),需要查找工资最高的3个员工信息,以下列格式输出: 乍眼一看,这很简单啊,对sal进行排序 ...
- irrlicht鬼火
中文鬼火 开源3d引擎 ogre osg等 libpng png图片处理 jpeg jpg图片库