• 1、JUC--volatile 关键字-内存可见性


    Java JUC简介

    Java 5.0 提供了 java.util.concurrent (简称
    JUC )包,在此包中增加了在并发编程中很常用
    的实用工具类,用于定义类似于线程的自定义子
    系统,包括线程池、异步 IO 和轻量级任务框架。
    提供可调的、灵活的线程池。还提供了设计用于
    多线程上下文中的 Collection 实现等

    线程实例:

    public class TestVoatile {
        
        public static void main(String[] args) {
            ThreadDemo td = new ThreadDemo();
            
            new Thread(td).start();
            while(true){
                if(td.isFlag()){
                    System.out.println("已启动");
                    break;
                }
            }
        }
    
    }
    
    
    class ThreadDemo implements Runnable{
        
        private boolean flag = false;
        
        public boolean isFlag(){
            return flag;
        }
        
        public void setFlag(boolean flag){
            this.flag = flag;
        }
    
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag = true;
            System.out.println("flag:" + isFlag());
        }
    }

    此时的main函数中是有两个线程的执行结果如下图所示:

    此时执行的是第一个线程

    while循环并没有执行

    此时设计内存可见性的问题

    共享数据

    同时存在缓存的问题

    此时线程1和main线程都有自己独立的缓存

    对于线程1来说首先需要要调用主存中的值,首先需要读取值到线程1中

    线程1读取值之后,并且要向主存中进行改值

    此时main线程到来,取出主存中的值

    所以此时main线程中的flag=false

    但是此时并没有及时进行对主存进行修改值

    此时使用线程睡眠:

            ThreadDemo td = new ThreadDemo();
            
            new Thread(td).start();
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
            while(true){
                if(td.isFlag()){
                    System.out.println("已启动");
                    break;
                }
            }
        }

    内存可见性问题

    多个线程操作共享数据问题,彼此不可见

    可以使用同步锁

    在取值时进行刷新数据

    public static void main(String[] args) {
            ThreadDemo td = new ThreadDemo();
            new Thread(td).start();
            while(true){
                synchronized (td) {
                    if(td.isFlag()){
                        System.out.println("已启动");
                        break;
                    }
                }
            }
        }

    此时使用同步锁机制,效率极低

    每次都会进行判断

    如果一个正在使用数据,另一个线程就会等待

    效率大大降低

    volatile关键字:

    当多个线程进行操作共享数据时,可以保证内存中的数据是可见的

    可以理解成直接对主存中的数据进行操作

    public class TestVoatile {
        
        public static void main(String[] args) {
            ThreadDemo td = new ThreadDemo();
            new Thread(td).start();
    
            while(true){
                    if(td.isFlag()){
                        System.out.println("已启动");
                        break;
                    }
            }
        }
    }
    class ThreadDemo implements Runnable{
        
        private volatile boolean flag = false;
        
        public boolean isFlag(){
            return flag;
        }
        
        public void setFlag(boolean flag){
            this.flag = flag;
        }
    
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag = true;
            
            System.out.println("flag:" + isFlag());
        }
    }

    相对于synchronized:

    Java 提供了一种稍弱的同步机制,即 volatile 变
    量,用来确保将变量的更新操作通知到其他线程。
    可以将 volatile 看做一个轻量级的锁

    前者是一种轻量级的同部策略

    1、volatile不具有互斥性(synchronized具有锁性值,只能有一个线程访问)

     2、volatile不具有原子性

  • 相关阅读:
    网页中这 10 种字体的运用方式,不会让人觉得 Low
    如何估算文章阅读时长?
    如何养出一个三十几亿身家的儿子
    2018免费的隐私保护工具
    写一份好的产品说明书
    安装 Ubuntu 19.10 选用 zfs 文件系统
    ESXI常用命令
    Harbor ($docker login) Error saving credentials
    Vue中使用matomo进行访问流量统计的实现
    eslint Cannot read property 'range' of null错误
  • 原文地址:https://www.cnblogs.com/Mrchengs/p/10792691.html
Copyright © 2020-2023  润新知