1. 程式人生 > >1、JUC--volatile 關鍵字-內存可見性

1、JUC--volatile 關鍵字-內存可見性

block rac 刷新 性問題 err bsp mage generated pre

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 關鍵字-內存可見性