1.volatile并不能保证线程安全性
声明为volatile的线程共享变量,并不能保证多线程在修改它值的时候,是安全的。
测试代码如下:
package com.wind.DbTec.sqlpkg; /** * volatile变量的正确用法 volatile变量不能保证变量修改的原子性,需要原子类的协助 基于解析可看链接地址 * http://www.cnblogs.com/yakun/p/3589437.html * http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html * http://www.blogjava.net/mstar/archive/2013/04/24/398351.html * * @author zhouyanjun * @version 1.0 2014-12-10 */ public class VolatileTest extends Thread { static class VolatileRunnable implements Runnable { private volatile Integer value = 0; public void run() { for (;;) { if (value >= 1000) { break; } value += 1; System.out.println(Thread.currentThread().getName() + " " + value); } } } public static void main(String[] args) { VolatileRunnable volatileRunnable = new VolatileRunnable(); Thread thread1 = new Thread(volatileRunnable); Thread thread2 = new Thread(volatileRunnable); Thread thread3 = new Thread(volatileRunnable); Thread thread4 = new Thread(volatileRunnable); thread1.start(); thread2.start(); thread3.start(); thread4.start(); } }
如上述代码,声明了一个线程共享的volatile的变量value,并在线程处理中累加它的值,同时启动4个线程,我们来看打印出的value值是否有相同值,如果有相同则表明volatile变量并不能保证线程安全。
笔者在多次执行下来,确实存在有相同值的情况(结果集太长就不贴出来了),所以volatile变量并不能保证线程安全。读者也可以自己测试下。
2.如何能使volatile变量线程安全呢?
要使volatile变量线程安全,是可以做到的,需要配合一些原子类的实现。比如笔者下面使用AtomicReferen-ceFieldUpdater类修改的上述代码,就可以保证volatile变量的线程安全。代码如下:
package com.wind.DbTec.sqlpkg; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; /** * volatile变量的正确用法 volatile变量不能保证变量修改的原子性,需要原子类的协助 基于解析可看链接地址 * http://www.cnblogs.com/yakun/p/3589437.html * http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html * http://www.blogjava.net/mstar/archive/2013/04/24/398351.html * * @author zhouyanjun * @version 1.0 2014-12-10 */ public class VolatileTest extends Thread { static class VolatileRunnable implements Runnable { private static final AtomicReferenceFieldUpdater<VolatileRunnable, Integer> nextUpdater = AtomicReferenceFieldUpdater .newUpdater(VolatileRunnable.class, Integer.class, "value"); // 增加一个AtomicReferenceFieldUpdater private volatile Integer value = 0; public void run() { for (;;) { if (value >= 1000) { break; } // 递增value当前值 Integer current = value; while (!nextUpdater.compareAndSet(this, current, current + 1)) { // 判断value值是否跟原值一样,一样则修改value值为current+1 current = value; } System.out.println(Thread.currentThread().getName() + " " + value); } } } public static void main(String[] args) { VolatileRunnable volatileRunnable = new VolatileRunnable(); Thread thread1 = new Thread(volatileRunnable); Thread thread2 = new Thread(volatileRunnable); Thread thread3 = new Thread(volatileRunnable); Thread thread4 = new Thread(volatileRunnable); thread1.start(); thread2.start(); thread3.start(); thread4.start(); } }
这种情况下,笔者多次测试下来,确实没出现相同值的情况,保证了volatile值的线程安全性。具体AtomicR-eferenceFieldUpdater类的实现可以从java.util.concurrent.atomic包下找到。
其实java.util.concurrent.atomic包下针对int,long,boolean,reference实现了好几个原子类,比如AtomicInteg-er,AtomicLong等。他们的原子更新方法实现,跟上述代码其中的这段很相似
Integer current = value; while (!nextUpdater.compareAndSet(this, current, current + 1)) { // 判断value值是否跟原值一样,一样则修改value值为current+1 current = value; }
比如AtomicInteger,它的值保存在成员变量value中,而且value是个volatile变量,如下:
private volatile int value;
它的getAndSet方法(此方法是返回当前值,然后设置新值)实现如下:
/** * Atomically sets to the given value and returns the old value. * * @param newValue the new value * @return the previous value */ public final int getAndSet(int newValue) { for (;;) { int current = get(); if (compareAndSet(current, newValue)) return current; } }
3.为什么volatile还需要配置原子类才能保证线程安全?
这个原因可能需要细究到java虚拟机的实现中去,笔者暂且止步,再次记一笔,以后有机会再做细究。
相关推荐
java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java ...
java volatile 关键字 学习
从JUC中的AQS引入,讲解Java volatile与AQS锁内存可见性
volatile
Java中的`volatile`关键字是用来修饰变量的,它主要用于解决多线程环境下的数据同步问题。在Java语言中,`volatile`变量提供了一种轻量级的同步机制,它确保了共享变量的可见性和有序性,但并不保证原子性。 **可见...
volatile关键字在Java编程语言中扮演着重要的角色,特别是在多线程环境下的同步和可见性问题。它是Java内存模型(JMM)的一部分,用于确保共享变量的可见性和有序性,但不保证原子性。 1. **volatile的可见性**:当...
Java中的`volatile`关键字是一个非常重要的并发编程工具,它的主要作用是确保共享变量在多线程环境下的可见性和有序性。下面将详细解释`volatile`的关键特性、它如何解决并发问题以及相关的`happens-before`原则。 ...
Java中的`volatile`关键字是用来解决多线程环境下的可见性和有序性问题的,它确保了共享变量在被修改后,其他线程能够立即看到最新的值,但并不保证操作的原子性。下面我们将深入探讨`volatile`关键字的原理、使用...
【Java面试题】volatile的作用
Java volatile的适用场景实例详解 Java volatile 关键字是 Java 并发编程中的一种重要机制,它提供了一种线程安全的方式来共享变量。volatile 变量具有 synchronized 的可见性特性,但是不具备原子性。这意味着线程...
Java Volatile 机制详解 Java 中的 volatile 关键字是一种轻量级的同步机制,在并发编程中扮演着重要的角色。了解 Java volatile 需要从内存模型基本概念开始。 内存模型基本概念 在计算机执行程序时,每条指令都...
Java Volatile关键字同步机制详解 Java Volatile关键字是Java语言中的一种同步机制,它可以保证在多线程环境下变量的可见性和原子性。通过使用Volatile关键字,可以确保在多线程环境下对变量的修改是可见的,并且...
在Java中,`volatile`关键字是用于解决并发问题的一个关键工具。它主要提供以下两个功能: 1. **可见性**:当一个线程修改了一个`volatile`变量时,这个修改会立即对其他所有线程可见。这意味着一旦一个线程修改了`...
Java 线程 volatile 关键字详解 Java™ 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。volatile 变量的同步性较差,但它有时更简单并且开销更低。volatile 变量可以被看作是一种 “程度较轻的 ...
Java中的`volatile`关键字是并发编程中至关重要的一个特性,它用于解决多线程环境下的可见性和有序性问题。在Java内存模型(JMM)中,`volatile`关键字确保了共享变量在多线程间的正确通信。 首先,我们来看`...
Java中的`volatile`关键字是用来解决多线程并发访问共享变量时的可见性和有序性问题的。在Java中,每个线程都有自己的工作内存,用于存储从主内存中复制的变量副本。如果没有同步措施,线程间无法直接感知彼此对共享...
Java中的`volatile`关键字在高并发编程中扮演着至关重要的角色,它提供了一种轻量级的同步机制,用于确保共享变量在多线程环境下的可见性。与`synchronized`关键字相比,`volatile`通常具有更低的开销,但它并不提供...