JavaWeb

JUC-001-volatile与内存可见性

2017-11-19  本文已影响10人  53b3f4658edc

JUC简介


内存可见性(Memory Visibility)

微信公众号:JavaWeb架构师

测试代码

package top.itcourse._volatile;

import org.junit.Test;
import org.omg.CORBA.FloatSeqHelper;

/*
 * 内存可见性(Memory Visibility):
 *      - 内存可见性(Memory Visibility)是指当某个线程正在使用对象状态而另一个线程在同时修改该状态,需要确保当一个线程修改了对象
 *          状态后,其他线程能够看到发生的状态变化。
 *      - 可见性错误是指当读操作与写操作在不同的线程中执行时,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根
 *          本不可能的事情。
 *      - 我们可以通过同步来保证对象被安全地发布。除此之外我们也可以使用一种更加轻量级的volatile 变量。 
 * 
 * 说明:
 *  线程对象中的属性是放在主存中的,线程修改/读取的属性是在自己线程的缓存中,当修改完毕之后再把值
 *  放回主存(不同的线程中去读取/修改的属性值,都是主存中的值)
 */


/*
 * 下面我们实现:
 *  线程一、二都读取到flag的初始值,然后在线程一的run方法中改变flag的值,但是线程二的flag值没有同步更新
 */
public class TestMemVisi {
    @Test
    public void testMemVisi() throws InterruptedException {
        // 2.新建实现了Runnable的对象
        MemVisi mv1 = new MemVisi();
        // 3.传递到Thread对象中start
        new Thread(mv1).start();
        
        while(true) {
            // 线程二:一直是false(因为线程一sleep的时候,它进来了,又因为是while循环,使得线程二根本没有机会再次从主存中去读取新值(可以说明
            //  没有线程间没有同步的通知、更新))
            if( mv1.isflag() ) {
                System.out.println("我在主线程打印,flag是true");
            }
            
            // Thread.sleep(50); // 加上这句话,就可以有机会去主存中读取新值
        }
    }
}

// 1.实现Runnable
class MemVisi implements Runnable {
    
    private boolean flag = false;
    
    public boolean isflag() {
        return flag;
    }

    public void setflag(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        // 让线程二先进去判断(while判断)       
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
        }
        
        // 线程一:     
        flag = true;
        System.out.println("flag: " + flag);
    }
}

运行结果:
flag: true


volatile 关键字

测试代码

package top.itcourse._volatile;

import org.junit.Test;

/*
 * volatile关键字:
 * Java提供了一种稍弱的同步机制,即volatile 变量,用来确保将变量的更新操作通知到其他线程。可以将volatile 看做一个轻量级的锁,但是又与锁有些不同:
 *      - 对于多线程,不是一种互斥关系(同步通知,所以效率会高一些)
 *      - 不能保证变量状态的“原子性操作”(下节讲)
 * 
 * 作用:多个线程操作共享数据时,保证内存中的数据是可见的
 */

/*
 * 解决同步通知、更新的问题:
 *  1.使用锁(效率低)
 *  2.
 */
public class TestVolatile {
    @Test
    public void testMemVisi() throws InterruptedException {
        // 2.新建实现了Runnable的对象
        MemVisia mv1 = new MemVisia();
        // 3.传递到Thread对象中start
        new Thread(mv1).start();
        
        while(true) {
            // 使用synchronized,可以解决,会去刷新缓存           
//          synchronized(mv1) {
//              if( mv1.isflag() ) {
//                  System.out.println("我在主线程打印,flag是true");
//                  break;
//              }
//          }
            
            if( mv1.isflag() ) {
                System.out.println("我在主线程打印,flag是true");
                break;
            }
            
        }
    }
}

// 1.实现Runnable
class MemVisia implements Runnable {
    
    // 使用volatile关键字,就可以解决了
    private volatile boolean flag = false;
    
    public boolean isflag() {
        return flag;
    }

    public void setflag(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        // 让线程二先进去判断(while判断)       
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
        }
        
        // 线程一:     
        flag = true;
        System.out.println("flag: " + flag);
    }
}

结果:
我在主线程打印,flag是true
flag: true


其它



源码下载:

关注下方微信公众号,
回复:
JUC.code
完整教程PDF版本下载
上一篇 下一篇

猜你喜欢

热点阅读