应该停止但无法停止的计算线程

如下线程示例,线程实例中while循环中的条件,在主线程中通过调用实例方法更新后,while循环并没有更新判断变量是否还成立。而是陷入了while(true)死循环.

import javafx.scene.paint.Stop;

/**
* @ClassName ThreadMemoryModeStopFailed
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/4/22.
*/
public class ThreadMemoryModeStopFailed {
private static long num = 0;
private static class StopFailed implements Runnable{
private boolean shouldSTop = false; public void setShouldSTop(boolean shouldSTop) {
this.shouldSTop = shouldSTop;
} @Override
public void run() {
while (!shouldSTop){
//当注释掉IO操作System.out.println 后,就会一直卡在num++一直算不会停止
// System.out.println(Thread.currentThread().getName() + "当前时间戳"+ System.currentTimeMillis());
num++;
}
System.out.println("运行结束");
}
}
public static void main(String[] args) throws InterruptedException {
StopFailed sr = new StopFailed();
Thread thread = new Thread(sr);
thread.start();
Thread.sleep(1000);
sr.setShouldSTop(true);
System.out.println("num结果:" + num);
}
}
上面的代码,如果在while循环中,我们加入了一行System.out.println之后,逻辑是正常的,线程可以被停止,但是如果注释了System.out.println之后,我们仅仅保留num++,这个时候我们的程序逻辑不正常了,一直陷入while死循环计算中。没有重新读取修改后的shouldSTop变量

java的内存模型

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
当子线程非常消耗CPU的时候,子线程的工作内存不会主动去和主内存中的共享变量同步这个就造成了我们刚刚出现的问题。但是当CPU消耗不是太厉害的时候,JVM会自动的把主内存中的共享变量同步到线程的工作内存中。
JVM有两种启动启动模式:
一种是client启动模式,还有之中是server启动模式。server模式启动比较慢,但是启动了之后程序的运行速度比较快,这个是因为Server模式在内存方面做优化就是上面的cache。client模式启动的时候比较快,内存使用比较少,但是程序运行的速度就比较慢

1、volatile关键字解决

volatile关键字解决工作内存和主内存变量不同步问题

private static volatile long num = 0;
我们发现子线程被停止了。这个是为什呢?volatile的作用,就是告诉我们的子线程,你在读取变量的时候,直接去主内存中读取,不要在工作内存中读取。

2、原子性操作对象,避免并发线程操作同一个对象值覆盖

volatile 关键字无法解决多线程操作同一个对象的原子性问题。原子性变量AtomicInteger 替代Integer 可以避免计算冲突错误,多线程操作此变量变为串行效果。 

示例:

import java.util.concurrent.atomic.AtomicInteger;

/**
* @ClassName ThreadMemoryModeVolatileNotSafe
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/4/23.
*/
public class ThreadMemoryModeVolatileNotSafe {
// private static volatile int num = 0; //非原子性变量
private static volatile AtomicInteger num = new AtomicInteger(0); //原子性变量 public static void main(String[] args) {
Runnable r = ()->{
for(int i=0; i< 1000; i++){
// num ++; //非原子性变量
num.addAndGet(1); //原子性整数自加一
}
};
for(int j=0; j<10; j++){
new Thread(r,"T"+j).start();
} try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " num:" + num);
/**
* 非原子性变量结果:不定
* 原子性变量结果:10000 反复测试符合预期
*/
}
}

java IO操作和计算操作:工作内存和主内存 volatile关键字作用;原子操作对象AtomicInteger ....的更多相关文章

  1. java线程内存模型,线程、工作内存、主内存

    转自:http://rainyear.iteye.com/blog/1734311 java线程内存模型 线程.工作内存.主内存三者之间的交互关系图: key edeas 所有线程共享主内存 每个线程 ...

  2. Java线程工作内存与主内存变量交换过程及volatile关键字理解

    Java线程工作内存与主内存变量交换过程及volatile关键字理解 1. Java内存模型规定在多线程情况下,线程操作主内存变量,需要通过线程独有的工作内存拷贝主内存变量副本来进行.此处的所谓内存模 ...

  3. Java内存模型与volatile关键字

    Java内存模型与volatile关键字 一).并发程序开发 并行程序的开发要涉及多线程.多任务间的协作和数据共享问题. 常用的并发控制:内部锁.重入锁.读写锁.信号量. 二).线程的特点 线程的特点 ...

  4. java volatile关键字作用及使用场景

    1. volatile关键字的作用:保证了变量的可见性(visibility).被volatile关键字修饰的变量,如果值发生了变更,其他线程立马可见,避免出现脏读的现象.如以下代码片段,isShut ...

  5. java io流 对文件操作

    检查文件是否存在 获取文件路径 获取文件大小 ...... 更多参考手册 //对文件的操作 //检查文件是否存在 //获取文件路径 //获取文件大小 //文件是否可读 //文件是否可写 //.... ...

  6. java IO流 对文件操作的代码集合

    Io流 按照分类 有两种分类 流向方向: 有输入流和输出流 按照操作类型有:字节流和字符流 按照流向方向 字节流的一些操作 //读文件 FileInputStream fis = new FileIn ...

  7. java IO流 Zip文件操作

    一.简介 压缩流操作主要的三个类 ZipOutputStream.ZipFile.ZipInputStream ,经常可以看到各种压缩文件:zip.jar.GZ格式的压缩文件 二.ZipEntry   ...

  8. Java IO编程——File文件操作类

    在Java语言里面提供有对于文件操作系统操作的支持,而这个支持就在java.io.File类中进行了定义,也就是说在整个java.io包里面,File类是唯一 一个与文件本身操作(创建.删除.重命名等 ...

  9. Java IO基础--File常用操作(递归)

    File中经常会使用递归方法打印属性结构.统计文件夹下文件个数.子文件夹个数以及文件大小,可以作为递归的应用练习. 递归的写法,百度一搜一大堆,这里我使用对javabean方式封装了一下: packa ...

随机推荐

  1. es的rest风格的api文档

    rest风格的api put http://127.0.0.1:9200/索引名称/类型名称/文档id (创建文档,指定文档id) post http://127.0.0.1:9200/索引名称/类型 ...

  2. Go语言核心36讲(Go语言实战与应用十五)--学习笔记

    37 | strings包与字符串操作 Go 语言不但拥有可以独立代表 Unicode 字符的类型rune,而且还有可以对字符串值进行 Unicode 字符拆分的for语句. 除此之外,标准库中的un ...

  3. 柯基数据通过Rainbond完成云原生改造,实现离线持续交付客户

    ​ ​1.关于柯基数据 南京柯基数据科技有限公司成立于2015年,提供一站式全生命周期知识图谱构建和运维.智能应用服务,致力于"链接海量数据,从大数据中挖掘智慧".帮助企业运用知识 ...

  4. Stupid && 祖传Fortran代码救赎之路(编译Dll)

    Stupid && 祖传Fortran代码救赎之路(编译Dll) gfortran编译动态库 在Windows平台下,Intel Fortran安装过于庞大且费事(现在集成到OneAP ...

  5. 洛谷 P4272 - [CTSC2009]序列变换(堆)

    洛谷题面传送门 u1s1 在我完成这篇题解之前,全网总共两篇题解,一篇使用的平衡树,一篇使用的就是这篇题解讲解的这个做法,但特判掉了一个点,把特判去掉在 BZOJ 上会 WA 一个点. 两篇题解都异常 ...

  6. CF932F Escape Through Leaf

    CF932F Escape Through Leaf 首先, $ O(n^2) $ dp 是很显然的,方程长这样: \[dp[u] = min\{dp[v] + a_u\times b_v\} \] ...

  7. char *p、char p[]、字符串的几个题目

    总结一下遇到的关于char *p.char p[]和字符串的题目: 例一:(指针的指针) 1 void getmemory(char **p) 2 { 3 p = (char *)malloc(100 ...

  8. 56-Remove Linked List Elements

    Remove Linked List Elements My Submissions QuestionEditorial Solution Total Accepted: 61924 Total Su ...

  9. 理解ASP.NET Core - 模型绑定&验证(Model Binding and Validation)

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 模型绑定 什么是模型绑定?简单说就是将HTTP请求参数绑定到程序方法入参上,该变量可以是简单类 ...

  10. Spark(三)【RDD中的自定义排序】

    在RDD中默认的算子sortBy,sortByKey只能真的值类型数据升序或者降序 现需要对自定义对象进行自定义排序. 一组Person对象 /** * Person 样例类 * @param nam ...