• java IO操作和计算操作:工作内存和主内存 volatile关键字作用;原子操作对象AtomicInteger ....


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

    如下线程示例,线程实例中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 反复测试符合预期
             */
        }
    }

  • 相关阅读:
    虚拟机vmware的连接方式以及IP端口,协议等概念
    python3爬虫--shell命令的使用和firefox firebug获取目标信息的xpath
    numpy的基本用法
    scrapy模拟请求头
    (1)python Scrapy爬虫框架
    flutter ui
    dart 类
    dart 基础
    黑苹果镜像下载地址
    android9.0请求异常
  • 原文地址:https://www.cnblogs.com/zhangmingda/p/14691914.html
Copyright © 2020-2023  润新知