• Java多线程中读写不一致问题


    问题:
    假设有个全局变量var初始化为0
    MyThread线程循环+1
    MyThread2线程检测到var大于10时退出循环
    问题来了,我们发现MyThread一直没有退出循环
    也就是说线程没有及时刷新内存
    解决方法:给全局变量添加 volatile关键字

    Java提供了volatile来保证可见性。当一个变量被volatile修饰后,表示着线程本地内存无效,当一个线程修改共享变量后他会立即被更新到主内存中,当其他线程读取共享变量时,它会直接从主内存中读取。

    点击查看代码
    
    abstract class ThreadMemo implements Runnable {
        private Thread t;
        protected String threadName;
    
        // public static int var = 0;
        volatile public static int var = 0; // 只需要添加volatile关键字就可以了
    
        public ThreadMemo(String name) {
            threadName = name;
            System.out.println("Creating " + threadName);
        }
    
        abstract public void run();
    
        public void start() {
            System.out.println("Starting " + threadName);
            if (t == null) {
                t = new Thread(this, threadName);
                t.start();
            }
        }
    
    }
    
    class MyThread extends ThreadMemo {
    
        MyThread(String name) {
            super(name);
        }
    
        public void run() {
            var = super.var;
            while(true) {
                var = var + 1;
                // sleep(50);
                // time.sleep(50);
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    System.out.println("Thread " + threadName + " interrupted.");
                }
                // System.out.println("mythread 1 var: " + var);
            }
            
        }
    }
    
    class MyThread2 extends ThreadMemo {
    
        MyThread2(String name) {
            super(name);
        }
    
        public void run() {
            var = super.var;
            while(true) {
                if(var < 10) {
                    // try {
                    //     Thread.sleep(1);
                    // } catch (InterruptedException e) {
                    //     System.out.println("Thread " + threadName + " interrupted.");
                    // }
                    // Object o = new Object();
    
                    continue;
                } 
                System.out.println("mythread2 var = " + var);
                break;
            }
        }
    }
    
    
    
    public class Test2 {
        // public static int var = 0;
        public static void main(String[] args) {
            ThreadMemo t1 = new MyThread("Thread-1");
            ThreadMemo t2 = new MyThread2("Thread-2");
    
            Thread a = new Thread(t1);
            Thread b = new Thread(t2);
            a.start();
            b.start();
        }
    }
    

    然后我们发现,给读线程的循环中添加一些语句,循环就能退出了
    V2EX上发现相同的问题 Java 多线程并发,线程什么时候会刷新 "工作内存"

    据说是遇到IO阻塞才会刷新内存

    个性签名:时间会解决一切
  • 相关阅读:
    MongoDB性能优化五步走之读书笔记
    Effective java 第十章 并发 避免过度同步 读书笔记
    Effective java 第三章对于所有对象都通用的方法(一) 读书笔记
    mongodb设计模式策略之读书笔记
    Effective java 第十章 并发 同步访问共享的可变数据 读书笔记
    搬运工生涯开端
    Effective java 第二章创建和销毁对象 读书笔记
    Mongodb聚合操作之读书笔记
    ArcGIS Engine 的插件式开发
    从一个AE画点的例子来看C#QI机制
  • 原文地址:https://www.cnblogs.com/lfri/p/15616108.html
Copyright © 2020-2023  润新知