码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-04-29 20:55:09      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:break   调用   imp   int   class   关键字   原子性   trace   睡眠   

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不具有原子性

 

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

标签:break   调用   imp   int   class   关键字   原子性   trace   睡眠   

原文地址:https://www.cnblogs.com/Mrchengs/p/10792691.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!