IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java工作内存与主内存同步时机 -> 正文阅读

[Java知识库]Java工作内存与主内存同步时机

概述

java工作内存和主内存模型

在多线程中,多个线程访问主存中的临界资源(共享变量)时,需要首先从主存中拷贝一份共享变量的值到自己的工作内存中,然后在线程中每次访问该变量时都是访问的线程工作内存(高速缓存)中的共享的变量副本,而不是每次都去主存读取共享变量的值(因为CPU的读写速率和主存读写速率相差很大,如果CPU每次都访问主存的话那么效率会非常低)。
java线程变量加载的大致流程是,将主内存的变量加载到工作内存进行处理,处理完毕后写会主内存。
在这里插入图片描述

工作内存和主内存数据交换时机

先看下如下代码,主线程运行时开启另一个线程,设置flag为true;但是发现主线程一直都未结束。
这个是大家在学习线程间可见性时,经常会遇到的例子,通常的解决办法是给flag,加上volatile关键字,保证变量的可见性;
对于线程安全问题,很多时候都不是必须的,但有一个奇怪的现象是,下面的程序每次运行都是必现,这又是什么原因导致的呢?

public class MemorySync {
    public static void main(String[] args) throws InterruptedException {
        ThreadDemo threadDemo = new ThreadDemo();
        new Thread(threadDemo, "t1").start();
        while (true) {
            if (threadDemo.getFlag()) {
                System.out.println("end task");
                break;
            }
        }
    }
}

class ThreadDemo implements Runnable {

    private boolean flag = false;

    @SneakyThrows
    @Override
    public void run() {
        TimeUnit.SECONDS.sleep(1);
        flag = true;
        System.out.println("set flag:" + flag);
    }

    public boolean getFlag() {
        return flag;
    }
}

不可见原因分析

  • 为什么主线程没有对ThreadDemo线程的变量变更可见呢?
    答:从内存模型可知,主线程一直用工作内存的变量,没有重新加载主内存被ThreadDemo线程改变的变量。
  • 为什么主线程一直没有重新加载主内存的变量呢?
    答:只有工作内存失效的时候,工作内存才会重新加载主内存的变量。

工作内存什么时候同步主内存的变量

  • 线程中释放锁,线程自己同步主存变量。
    当前线程释放锁后,当前线程会去加载主存变量。
  • 线程上下文切换。
  • CPU有空闲时间时(比如线程休眠、IO操作等)

上面代码工作内存重新加载主内存方案

  1. 加volatile关键字
class ThreadDemo implements Runnable {
    // 方案1:添加volatile关键字
    private volatile boolean flag = false;

    @SneakyThrows
    @Override
    public void run() {
        TimeUnit.SECONDS.sleep(1);
        flag = true;
        System.out.println("set flag:" + flag);
    }

    public boolean getFlag() {
        return flag;
    }
}
  1. main线程加休眠时间
public class MemorySync {
    public static void main(String[] args) throws InterruptedException {
        ThreadDemo threadDemo = new ThreadDemo();
        new Thread(threadDemo, "t1").start();
        while (true) {
            if (threadDemo.getFlag()) {
                System.out.println("end task");
                break;
            }
            // 添加休眠操作,使CPU有空闲时间
            TimeUnit.SECONDS.sleep(1);
        }
    }
}
  1. IO操作等,比如File file = new File(“F://temp.txt”)
public class MemorySync {
    public static void main(String[] args) throws InterruptedException {
        ThreadDemo threadDemo = new ThreadDemo();
        new Thread(threadDemo, "t1").start();
        while (true) {
            if (threadDemo.getFlag()) {
                System.out.println("end task");
                break;
            }
            // 添加io操作,让CPU有空闲时间
            File file = new File("F://text.txt");
        }
    }
}
  1. 线程释放锁
 public class MemorySyncVolatile {
    public static void main(String[] args) throws InterruptedException {
        ThreadDemo1 threadDemo = new ThreadDemo1();
        new Thread(threadDemo, "t1").start();
        while (true) {
        	// 线程释放锁
            synchronized (threadDemo) {
                if (threadDemo.getFlag()) {
                    System.out.println("end task");
                    break;
                }
            }

        }
        TimeUnit.SECONDS.sleep(5);
    }
}
// 或者
public class MemorySyncVolatile {
    public static void main(String[] args) throws InterruptedException {
        ThreadDemo1 threadDemo = new ThreadDemo1();
        new Thread(threadDemo, "t1").start();
        Lock lock = new ReentrantLock();
        while (true) {
            lock.lock();
            if (threadDemo.getFlag()) {
                System.out.println("end task");
                break;
            }
            // 释放锁
            lock.unlock();
        }
        TimeUnit.SECONDS.sleep(5);
    }
}

参考

线程的工作内存与主内存同步时机
浅析JMM线程工作内存什么时候读取主存变量

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-11 16:17:11  更:2022-05-11 16:17:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:01:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码