Volatile介绍

Volatile介绍

标签: 多线程


volatile的特点

1.使变量在多个线程中可见.即,使多个线程从公共堆栈中获得变量值。
2.volatile只用于修饰变量.synchronized可以修饰方法,变量和类.
3.volatile不能保证原子性. 它唯一的作用就是 使 私有线程 从 公共堆栈中获取数据。仅仅保证读取的数据最新.
4.多线程访问volatile不会阻塞,而synchronized会导致阻塞.
5.synchronized 具有 互斥性 和 可见性。 即,使用synchronized有volatile的可见性的效果.

下面用两个例子说明volatile的特点

增加变量可见性


public class VolatileDemo {

    public static void main(String[] args) {
        ServicePart servicePart = new ServicePart();

        VolatileThreadOne one = new VolatileThreadOne();
        VolatileThreadTwo two = new VolatileThreadTwo();
        one.setService(servicePart);
        two.setServicePart(servicePart);

        Thread t1 = new Thread(one);
        Thread t2 = new Thread(two);
        t1.start();
        t2.start();

    }

}

class ServicePart {
    //加入volatile修饰之后,不同线程获取flag值时,会从公共堆栈中获取,即,最新的值.
    //即,当t2线程设置的flag的值为false,t1线程会马上知道flag的值为flase.
    //  否则,可能会导致,t1线程一直在其私有数据栈中 获取flag的值,即,一直为true.
    volatile private boolean flag = true;


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

    public void doHomework() {
        while (flag) {
            System.out.println("我一直在,根本停不下来");
        }
        System.out.println("停停停");
    }

}

class VolatileThreadOne implements Runnable{
    ServicePart ServicePart;

    public void setService(ServicePart ServicePart) {
        this.ServicePart = ServicePart;
    }

    @Override
    public void run() {
        this.ServicePart.doHomework();
    }
}

class VolatileThreadTwo implements Runnable{
    ServicePart servicePart;

    public void setServicePart(ServicePart servicePart) {
        this.servicePart = servicePart;
    }

    @Override
    public void run() {
        this.servicePart.setFlag(false);
    }
}

证明 volatile 不具有原子性

/**
 *  这个主要证明 volatile 不具有原子性.
 *      即: 会出现多线程 异步操作,出现脏读.
 *
 *          在方法中,原子类方法执行顺序随机.
 *
 *      控制台输出顺序乱序,即异步操作.
 */

/**
 * Created by static-mkk on 10/4/2018.
 */
public class VolatileDemoTwo {

    public static void main(String[] args) {
        VolatileService volatileService = new VolatileService();

        VolatileDemoTwoThreadOne t1 = new VolatileDemoTwoThreadOne();
        t1.setVolatileService(volatileService);

        VolatileDemoTwoThreadTwo t2 = new VolatileDemoTwoThreadTwo();
        t2.setVolatileService(volatileService);

        t1.start();
        t2.start();
    }
}

class VolatileService{
    volatile public int number;
    public void sayNumber(){
        while(number < 1000){

            number++;
            if(number%50==0){
                System.out.println(number);
            }
        }
    }
}

class VolatileDemoTwoThreadOne extends Thread{

    VolatileService volatileService;

    public void setVolatileService(VolatileService volatileService) {
        this.volatileService = volatileService;
    }

    @Override
    public void run() {
        super.run();
        volatileService.sayNumber();
    }
}

class VolatileDemoTwoThreadTwo extends Thread{

    VolatileService volatileService;

    public void setVolatileService(VolatileService volatileService) {
        this.volatileService = volatileService;
    }

    @Override
    public void run() {
        super.run();
        volatileService.sayNumber();
    }
}

tips:如果您用IDE来运行带代码,请把JVM的设置为-server模式,该模式下,为了线程执行效率,线程一直在私有堆栈中获取数据。导致flag一直为true.所以,虽然另外的线程把flag设置成了true,只是公共堆栈中flag设置成功,但是私有堆栈中flag依旧没变。所以此时需要用volatile来从公共堆栈中读取最新数据。这也是volatile的作用。唯一作用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值