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

如下线程示例,线程实例中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. Qt5 connect 重载信号和槽

    转载文章超哥的经验之谈---Qt5 connect使用之"重载信号和槽" 在Qt4中,关联信号与槽是要使用到SIGNAL()和SLOT()这两个宏. QLabel *label = ...

  2. 数值分析:幂迭代和PageRank算法(Numpy实现)

    1. 幂迭代算法(简称幂法) (1) 占优特征值和占优特征向量 已知方阵\(\bm{A} \in \R^{n \times n}\), \(\bm{A}\)的占优特征值是比\(\bm{A}\)的其他特 ...

  3. 统计学习3:线性支持向量机(Pytorch实现)

    学习策略 软间隔最大化 上一章我们所定义的"线性可分支持向量机"要求训练数据是线性可分的.然而在实际中,训练数据往往包括异常值(outlier),故而常是线性不可分的.这就要求我们 ...

  4. Break up CF700C

    Break up CF700C 首先考虑只能删一条边的做法,我们可以找出所有的桥,然后随便跑一条 S 到 T 路径,如果这条路径上有桥就说明可以,否则不行 发现这个做法其实是 O(M) 的 那么可以先 ...

  5. Python三元表达式,列表推导式,字典生成式

    目录 1. 三元表达式 2. 列表推导式 3. 字典生成式 3.1 字典生成式 3.2 zip()方法 1. 三元表达式 """ 条件成立时的返回值 if 条件 else ...

  6. kubernetes部署 flannel网络组件

    创建 flannel 证书和私钥flannel 从 etcd 集群存取网段分配信息,而 etcd 集群启用了双向 x509 证书认证,所以需要为 flanneld 生成证书和私钥. cat > ...

  7. Java 数据类型转化

    目录 Java类型转化 基本数据类型自动类型转换 自动类型提升 强制类型转换 - 自动类型提升的逆运算 int与long int类型与String类型 int类型转换成String类型 方法1:+ 拼 ...

  8. Spring.DM版HelloWorld

    本文主要描述使用Spring.DM2.0,创建OSGi的HelloWorld演示程序,理解Spring.DM的OSGi框架实现机制.   环境描述: 项目 版本 Eclipse 3.7.x JDK 1 ...

  9. navicat突然连接不上远程linux服务器上的mysql

    我linux服务器上的mysql是docker安装的,突然有一天我的navicat连接不上服务器上的mysql,于是开始了下面一系列的修复 1.首先登录服务器上mysql,看是否能正常登录,我发现不能 ...

  10. 【Services】【Web】【tomcat】配置tomcat支持https传输

    1. 基础: 1.1. 描述:内网的tomcat接到外网nginx转发过来的请求之后需要和外网的客户端进行通讯,为了保证通讯内容的安装,使用tomcat使用https协议. 1.2. 链接:http: ...