多线程入门(二):线程安全的可见性以及volatile关键字

    上文说到线程安全的两个特性,一是原子性,而是可见性,什么是可见性呢?

    //不可见性

    在多个线程操作同一个变量时,其它线程对一个线程的变量操作是不可见的,原因就涉及到JVM的内存模型了。

    在介绍JVM内存模型时,我们经常提到内存为线程私有,所谓的线程私有,就是在线程运行时,JVM会为线程开辟一块专属于该线程的“工作内存”,用于存放栈内存,同时也将线程需要用到的主内存中的变量copy一份到工作内存中,当线程工作完后,再将变量写回主内存,在这个过程中,其它线程只能读取到主内存中的变量,所以说是不可见的。很显然的,synchronize关键字不仅实现了原子性,也实现了可见性,因为在解锁后,线程会把变量写回到主内存中,等待的线程会把写回主内存的变量再取出来,也就知道了上一个线程的操作,但是由于加锁的原因,会导致代码很复杂,效率会很低。

    //可见性

    volatile关键字的作用就是让线程之间可见,强制让线程将修改过的变量刷新至主内存中,另外,当主内存中变量修改,其它线程工作内存中的变量就会失效,且当再次读取该变量时,需要去主内存中重新读取变量的值。

    所谓可见性,就是读操作时,对其他线程的写操作是可见的。

    来看一段代码:

public class Demo extends Thread{
    public void setIsrun(boolean isrun) {
        this.isrun = isrun;
    }

    private boolean isrun = true;
    public void run()
    {
        System.out.println("线程开始了!!!");
        while(isrun==true)
        {

        }
        System.out.println("线程结束了!!!");
    }

    public static void main(String args[]) throws InterruptedException {
        Demo thead = new Demo();
        thead.start();
        Thread.sleep(3000);
        thead.setIsrun(false);
        System.out.println(thead.isrun);
    }
}

    没有对变量加volatile关键字修饰下,处理这么一个逻辑:写一个线程,当isrun为true的时候运行(isrun初始值为true),在主线程中先运行该线程,然后再修改isrun变量为false。启动就会发现,线程无法停下,但是isrun已经修改过了(当JVM未被优化的时候,在cmd中输入java -version,会显示jvm为客户端,此时线程会停下,私以为,因为启用“工作内存”是JDK1.5以后的版本,若未优化,则还是会在主内存中读写,看不出效果,资料来源于:传送门)。

    然后再将isrun改为volatile修饰过的,此时线程才会停下来,volatile使得该变量可见。

    重点:volatile仅仅只能提供多个线程之间的可见性,但是不会让线程具有原子性,要实现线程的原子性,还是得靠synchronize关键字,volatile对synchronize不具有替代作用。

    因为,即使volatile是变量在线程间可见,但是他的任何操作还是分为多步骤,如i++,还是先取出i,然后++,最后写回,若有其他线程在第一步取出阶段便读取了数据,也写回,但是晚于前一个线程,由于这个过程没有再次进行读的操作,所以是不会刷新工作内存的i的,导致明明是加了两次的操作,却只得到加了一次的结果,这时是线程不安全的。

    volatile相对于synchronize,性能更加的好,netty底层便是使用大量volatile进行编写,可见其性能。虽然无法替代synchronize,但是在大多数可见性的业务上,可以使用volatile关键字,如状态标志变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值