关于volatile的用法

拯救司马 2014-08-15 07:05:12
在百度上查了很多资料,基本都有讲到volatile的用法,可是最可悲的是,除了阻止编译器的优化外,其他的所有用法我都看不懂。。。都讲得太简单了,根据例子中提供的代码完全想不到是不是实现多线程的安全并发的。
不知道有没有大牛能三言两语点破我的困境?

另外关于一次性安全发布(one-time safe publication),我也是查了资料,大概明白了安全发布是保证对象的正确对外输出,但到底什么样的情况会导致不安全的发布还是不懂,能举个例子么? 以及这个例子会造成最直接的后果啥的?
...全文
394 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
nklofy 2014-08-19
  • 打赏
  • 举报
回复
引用 14 楼 xiangnan129 的回复:
[quote=引用 11 楼 nklofy 的回复:] [quote=引用 4 楼 xiangnan129 的回复:] 就我现在的能力和理解是这样的: volatile主要用处是在并发情况下,保证每个线程拿到的数据是一致的,也就是说是对加锁,单例的一种更加严格的保证。 在你每次需要这个数据的时候,它都会去内存中取,如果更新了数据,它会实时的更新内存中的数据。 所以就保证了多线程下的数据一致性。如果将变量用volatile修饰,将会告诉jvm,不会保存这个变量的私有本地变量值。 这样导致的结果就是效率会低一点,因为每次都会去比较,都会去重新获取。 这是我的一些个人见解,还不是很透彻,仅供参考,如果楼主有了更加深入的理解,也可以一起交流学习。
主要是保证处理器不会做一些有害并发的优化。比如不会改变相关代码的顺序,不会CPU缓存。但不算是加锁。只是保证修改之后在内存立即可见。不能保证并发安全性。比如第一个线程同第二个线程同时都取值,然后一个线程修改了。第二个线程再取值可以看到最新更新,但是这个更新的过程没有加锁,不保证(取值+修改)整个过程的原子性。也就是说,不是被第一个线程锁住来修改的。假如两个线程同时做(取值+改)的动作,就不是线程安全的。[/quote] 加锁会影响效率,而在非原子性操作上,使用volatile并不能保证并发的线程安全。那有什么好的处理方式吗[/quote] 现代处理器都有“检查并交换”的指令,检查变量的值若等于A,则代换为B。整个过程是原子性的。在机器码的层面上实现了线程安全。具体到java,尽量用原子类型,名字都是AtomicXXX。推荐看看《java并发实战》这本书。基本上这些问题都讲过了。
scott_129 2014-08-18
  • 打赏
  • 举报
回复
引用 11 楼 nklofy 的回复:
[quote=引用 4 楼 xiangnan129 的回复:] 就我现在的能力和理解是这样的: volatile主要用处是在并发情况下,保证每个线程拿到的数据是一致的,也就是说是对加锁,单例的一种更加严格的保证。 在你每次需要这个数据的时候,它都会去内存中取,如果更新了数据,它会实时的更新内存中的数据。 所以就保证了多线程下的数据一致性。如果将变量用volatile修饰,将会告诉jvm,不会保存这个变量的私有本地变量值。 这样导致的结果就是效率会低一点,因为每次都会去比较,都会去重新获取。 这是我的一些个人见解,还不是很透彻,仅供参考,如果楼主有了更加深入的理解,也可以一起交流学习。
主要是保证处理器不会做一些有害并发的优化。比如不会改变相关代码的顺序,不会CPU缓存。但不算是加锁。只是保证修改之后在内存立即可见。不能保证并发安全性。比如第一个线程同第二个线程同时都取值,然后一个线程修改了。第二个线程再取值可以看到最新更新,但是这个更新的过程没有加锁,不保证(取值+修改)整个过程的原子性。也就是说,不是被第一个线程锁住来修改的。假如两个线程同时做(取值+改)的动作,就不是线程安全的。[/quote] 加锁会影响效率,而在非原子性操作上,使用volatile并不能保证并发的线程安全。那有什么好的处理方式吗
nklofy 2014-08-18
  • 打赏
  • 举报
回复
引用 4 楼 xiangnan129 的回复:
就我现在的能力和理解是这样的: volatile主要用处是在并发情况下,保证每个线程拿到的数据是一致的,也就是说是对加锁,单例的一种更加严格的保证。 在你每次需要这个数据的时候,它都会去内存中取,如果更新了数据,它会实时的更新内存中的数据。 所以就保证了多线程下的数据一致性。如果将变量用volatile修饰,将会告诉jvm,不会保存这个变量的私有本地变量值。 这样导致的结果就是效率会低一点,因为每次都会去比较,都会去重新获取。 这是我的一些个人见解,还不是很透彻,仅供参考,如果楼主有了更加深入的理解,也可以一起交流学习。
主要是保证处理器不会做一些有害并发的优化。比如不会改变相关代码的顺序,不会CPU缓存。但不算是加锁。只是保证修改之后在内存立即可见。不能保证并发安全性。比如第一个线程同第二个线程同时都取值,然后一个线程修改了。第二个线程再取值可以看到最新更新,但是这个更新的过程没有加锁,不保证(取值+修改)整个过程的原子性。也就是说,不是被第一个线程锁住来修改的。假如两个线程同时做(取值+改)的动作,就不是线程安全的。
拯救司马 2014-08-18
  • 打赏
  • 举报
回复
引用 8 楼 qq393558792 的回复:
[quote=引用 1 楼 iHTML 的回复:] 你知道happen-before不?读、写volatile变量就会触发内存可见性更新,保证你看到最新数据。
那关于安全发布你知道些什么吗? 看下面这段代码
public class BackgroundFloobleLoader {
    public volatile Flooble theFlooble;

    public void initInBackground() {
        // do lots of stuff
        theFlooble = new Flooble();  // this is the only write to theFlooble
    }
}

public class SomeOtherClass {
    public void doWork() {
        while (true) { 
            // do some stuff...
            // use the Flooble, but only if it is ready
            if (floobleLoader.theFlooble != null) 
                doSomething(floobleLoader.theFlooble);
        }
    }
}
原文作者说如果 theFlooble 引用不是 volatile 类型,doWork() 中的代码在解除对 theFlooble 的引用时,将会得到一个不完全构造的 Flooble。 这句话我看不懂,什么叫做一个不完全构造的Flooble,这段代码不完整,能帮我改一下让我可以在程序中模拟出异常的状况吗?[/quote] 哦。。。我不纠结了,时机到了自然就懂了[img=https://forum.csdn.net/PointForum/ui/scripts/csdn/Plugin/003/monkey/2.gif] [/img] 虽然没解决,不过就你回答了两次,大部分分给你了
nklofy 2014-08-18
  • 打赏
  • 举报
回复
引用 8 楼 qq393558792 的回复:
[quote=引用 1 楼 iHTML 的回复:] 你知道happen-before不?读、写volatile变量就会触发内存可见性更新,保证你看到最新数据。
那关于安全发布你知道些什么吗? 看下面这段代码
public class BackgroundFloobleLoader {
    public volatile Flooble theFlooble;

    public void initInBackground() {
        // do lots of stuff
        theFlooble = new Flooble();  // this is the only write to theFlooble
    }
}

public class SomeOtherClass {
    public void doWork() {
        while (true) { 
            // do some stuff...
            // use the Flooble, but only if it is ready
            if (floobleLoader.theFlooble != null) 
                doSomething(floobleLoader.theFlooble);
        }
    }
}
原文作者说如果 theFlooble 引用不是 volatile 类型,doWork() 中的代码在解除对 theFlooble 的引用时,将会得到一个不完全构造的 Flooble。 这句话我看不懂,什么叫做一个不完全构造的Flooble,这段代码不完整,能帮我改一下让我可以在程序中模拟出异常的状况吗?[/quote] 没完整的代码不是很清楚,但是猜测意思是说两个SomeOtherClass的线程,一个线程还在初始化Flooble,另一个线程提前引用了Flooble,第二个线程就把flooble当作了null。这样就会初始化两次,就会有错误。
拯救司马 2014-08-18
  • 打赏
  • 举报
回复
引用 11 楼 nklofy 的回复:
[quote=引用 4 楼 xiangnan129 的回复:] 就我现在的能力和理解是这样的: volatile主要用处是在并发情况下,保证每个线程拿到的数据是一致的,也就是说是对加锁,单例的一种更加严格的保证。 在你每次需要这个数据的时候,它都会去内存中取,如果更新了数据,它会实时的更新内存中的数据。 所以就保证了多线程下的数据一致性。如果将变量用volatile修饰,将会告诉jvm,不会保存这个变量的私有本地变量值。 这样导致的结果就是效率会低一点,因为每次都会去比较,都会去重新获取。 这是我的一些个人见解,还不是很透彻,仅供参考,如果楼主有了更加深入的理解,也可以一起交流学习。
主要是保证处理器不会做一些有害并发的优化。比如不会改变相关代码的顺序,不会CPU缓存。但不算是加锁。只是保证修改之后在内存立即可见。不能保证并发安全性。比如第一个线程同第二个线程同时都取值,然后一个线程修改了。第二个线程再取值可以看到最新更新,但是这个更新的过程没有加锁,不保证(取值+修改)整个过程的原子性。也就是说,不是被第一个线程锁住来修改的。假如两个线程同时做(取值+改)的动作,就不是线程安全的。[/quote] 其实关键是用volatile修饰一个对象时, 一次性安全发布我不懂,不知道怎样的异常情况叫做非安全发布? 具体看8楼
dengziyuan 2014-08-16
  • 打赏
  • 举报
回复
不想让变量被改变的时候使用!
scott_129 2014-08-16
  • 打赏
  • 举报
回复
就我现在的能力和理解是这样的: volatile主要用处是在并发情况下,保证每个线程拿到的数据是一致的,也就是说是对加锁,单例的一种更加严格的保证。 在你每次需要这个数据的时候,它都会去内存中取,如果更新了数据,它会实时的更新内存中的数据。 所以就保证了多线程下的数据一致性。如果将变量用volatile修饰,将会告诉jvm,不会保存这个变量的私有本地变量值。 这样导致的结果就是效率会低一点,因为每次都会去比较,都会去重新获取。 这是我的一些个人见解,还不是很透彻,仅供参考,如果楼主有了更加深入的理解,也可以一起交流学习。
S117 2014-08-16
  • 打赏
  • 举报
回复
参考《java并发编程实践》
结贴是美德 2014-08-16
  • 打赏
  • 举报
回复
引用 8 楼 qq393558792 的回复:
[quote=引用 1 楼 iHTML 的回复:] 你知道happen-before不?读、写volatile变量就会触发内存可见性更新,保证你看到最新数据。
那关于安全发布你知道些什么吗? 看下面这段代码
public class BackgroundFloobleLoader {
    public volatile Flooble theFlooble;

    public void initInBackground() {
        // do lots of stuff
        theFlooble = new Flooble();  // this is the only write to theFlooble
    }
}

public class SomeOtherClass {
    public void doWork() {
        while (true) { 
            // do some stuff...
            // use the Flooble, but only if it is ready
            if (floobleLoader.theFlooble != null) 
                doSomething(floobleLoader.theFlooble);
        }
    }
}
原文作者说如果 theFlooble 引用不是 volatile 类型,doWork() 中的代码在解除对 theFlooble 的引用时,将会得到一个不完全构造的 Flooble。 这句话我看不懂,什么叫做一个不完全构造的Flooble,这段代码不完整,能帮我改一下让我可以在程序中模拟出异常的状况吗?[/quote] 我曾经也想模拟出书中提到的各种异常,但是没有几个能复现的。。。
拯救司马 2014-08-16
  • 打赏
  • 举报
回复
引用 1 楼 iHTML 的回复:
你知道happen-before不?读、写volatile变量就会触发内存可见性更新,保证你看到最新数据。
那关于安全发布你知道些什么吗? 看下面这段代码
public class BackgroundFloobleLoader {
    public volatile Flooble theFlooble;

    public void initInBackground() {
        // do lots of stuff
        theFlooble = new Flooble();  // this is the only write to theFlooble
    }
}

public class SomeOtherClass {
    public void doWork() {
        while (true) { 
            // do some stuff...
            // use the Flooble, but only if it is ready
            if (floobleLoader.theFlooble != null) 
                doSomething(floobleLoader.theFlooble);
        }
    }
}
原文作者说如果 theFlooble 引用不是 volatile 类型,doWork() 中的代码在解除对 theFlooble 的引用时,将会得到一个不完全构造的 Flooble。 这句话我看不懂,什么叫做一个不完全构造的Flooble,这段代码不完整,能帮我改一下让我可以在程序中模拟出异常的状况吗?
y1018799688 2014-08-16
  • 打赏
  • 举报
回复
threenewbee 2014-08-15
  • 打赏
  • 举报
回复
http://www.ibm.com/developerworks/cn/java/j-jtp06197.html
as1dasd11 2014-08-15
  • 打赏
  • 举报
回复
http://www.ticmy.com/?p=5 看完这篇文章 希望你能有点感触。
结贴是美德 2014-08-15
  • 打赏
  • 举报
回复
你知道happen-before不?读、写volatile变量就会触发内存可见性更新,保证你看到最新数据。

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧