跟着实例学习java多线程5-初识volatile变量

同步机制可以保证原子操作和内存可见性,但是同步机制对变量的访问性能是我们不得不考虑的问题,java语言提供了一种弱同步机制,volatile变量。

它的原理大致是这样的,当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量总会返回最新写入的值。(参考《java并发编程实践》一书)

让我们来看一个实例:

package com.home.thread;
/**
 * @author gaoxu
 *
 */
public class ThreadStart {

 private static class ReaderThread extends Thread{

  public void run(){
   SafeThread.setNumber(1);
  }
 }
 private static class ReaderThread1 extends Thread{
  public void run(){
	long start = System.currentTimeMillis();
    System.out.println("="+SafeThread.getNumber());
    long endTime = System.currentTimeMillis()-start;
    System.out.println("所用时间:"+endTime);
  }
 }

 public static void main(String[] para){

  new ReaderThread().start();
  new ReaderThread1().start();
 }
}
package com.home.thread;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author gaoxu
 *
 */
public class SafeThread {
	volatile static int number;

	public  static  int getNumber() {
			return number;
	}

	public  static  void setNumber(int number) {

		SafeThread.number = number;
	}

}

这段代码的运行结果是 1 ,也就是说getNumber保证获取到的都是number变量最新的内存值,这都是volatile的功劳,我们可以把对volatile变量的访问想象成是synchronized的set和get操作(虽然同步远比volatile的内存可见性强),volatile的使用看似很方便,但是它的使用是有局限性的。

volatile变量的使用只能保证变量的内存可见性,不能保证变量的原子性,所以volatile变量的使用有如下条件:

对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。

该变量不会与其他的状态变量一起纳入不变条件中。

在访问变量时不需要加锁。

我们看到上面代码的例子完全符合他的这些条件,所以这个例子是完全可以使用volatile的。

另外我们也在代码中加了测试时间的代码:

每种方式运行10遍。

得出的结论是使用volatile变量比同步平均快1毫秒。(精确度不高)



时间: 2024-10-12 13:40:35

跟着实例学习java多线程5-初识volatile变量的相关文章

Java多线程 -- 正确使用Volatile变量

Java 语言中的 volatile 变量可以被看作是一种 "程度较轻的 synchronized":与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分.本文介绍了几种有效使用 volatile 变量的模式,并强调了几种不适合使用 volatile 变量的情形. 锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility).互斥即一次只允许一

跟着实例学习java多线程-2

上一篇文章我们通过一个实例来说明了并发编程为什么要做同步处理,下面我们再来巩固一下. 对象如果拥有可变状态的变量,并且被多线程访问,那么这个时候我们要对可变状态变量的状态改变做原子操作处理. 锁机制是保证这样的操作的一个有效的方法,它可以保证变量的状态在被更新时是在一个原子操作中进行的. java提供了一种内置锁机制来支持原子性:同步代码块(Synchronized Block). 同步代码块包括两个部分:一个是作为锁的对象引用,一个是作为由这个锁保护的代码块. 让我们在来回忆上一篇文章最后的问

跟着实例学习java多线程4-内存可见性

前三篇我们主要说了多线程访问共享可变状态时需要进行正确的同步处理,保证同一时刻只有一个线程访问相同的数据,我们使用synchronized关键字来实现原子性操作. 今天我们在来认识一下同步的另一个重要方面:内存可见性,这个概念其实很好理解,就是保证在同一个时刻,共享可变状态对访问它的线程呈现出自己最新的状态变化. 我们经常遇到的情景是这样的,一个全局变量计数器,一个线程负责更新该数值,另一些线程获取这个值,那么可见性就是获取值的线程,可以获取到更新线程更新的最新的值. 让我们先来看一个例子,在没

跟着实例学习java多线程6-如何正确发布线程安全的对象

我们前面所讲的一切其实都只是为了一个目标那就是能正确发布一个线程安全的对象. 一:线程封闭 这个很好理解如果一个变量是在一个线程中完成的状态改变,那么这个变量肯定是线程安全的. 我们常使用的是栈封闭和ThreadLocal类. 在java运行时内存区中有一个虚拟机栈,栈封闭说的就是这个栈,这个栈是线程私有的,它的生命周期与线程相同.虚拟机栈描述描述的是java方法执行的内存模型:每个方法被执行的时候会同时创建一个栈帧用于存储局部变量.操作数栈等.每一个方法被调用直至执行完成的过程,就对应着一个栈

跟着实例学习java多线程7-对象的组合发布

我们学习线程安全与同步的知识目的就是要实现一些可复用组件或编写出更大的程序. java中类是对象抽象,那么怎么实现一个线程安全类是我们必须要知道的并正确使用的技术. 在设计线程安全类的过程中,需要包含以下三个基本元素: 找出构成对象状态的所有变量. 找出约束状态变量的不变性条件. 建立对象状态的并发访问管理策略. package com.home.thread.thread7; import com.home.thread.safe; public class Counter { /** * @

跟着实例学习java多线程8-同步容器类的问题

我们知道java有很多线程安全的容器类,我们也知道如果把可变状态的管理交给这些线程安全类来管理就可以实现线程安全,但是我们还可能遇到不可想象的问题. 例如: package com.home.thread.thread8; import java.util.Vector; /** * @author gaoxu * 实践出真知! */ public class VectorQueue { private static VectorQueue instance; private static Ve

跟着实例学习java多线程9-定时任务实例

定时任务是我们经常遇到的业务场景,我们有很多的功能都需要这样的技术来实现,例如:定时获取一些数据push出去,定时处理一些清理任务,定时检查某个值等.那么我们该怎么实现,在实现中又该注意一些什么? 定时任务就是另开一个线程来执行,其实也是并发的一类,大家可能不好理解,说定时不就是到时间执行一下,怎么还会产生并发,这里主要是看两个指标,一是看执行频率,二是看每次执行的时间,如果执行频率高并且执行任务又会很耗时,那么这时候就形成了并发,当然还有一种情况那就是,定时的job中调用其它服务的方法,而正常

跟着实例学习java多线程-3

同步代码块是一种有效实现操作原子性的方法,上一章我们讲了一些同步的原子操作的基础. 现在我们回忆一下上一章的两个问题. 1:不同的synchronized的写法有什么区别,又该怎么写创建线程的代码呢? 以class实例对象作为锁的写法 写法1 package com.home.thread; /** * @author gaoxu * */ public class SafeThread { @safe public void testPrint(){ synchronized(SafeThre

并行编程之多线程共享非volatile变量,会不会可能导致线程while死循环

背景 大家都知道线程之间共享变量要用volatile关键字.但是,如果不用volatile来标识,会不会导致线程死循环?比如下面的伪代码: static int flag = -1; void thread1(){ while(flag > 0){ //wait or do something } } void thread2(){ //do something flag = -1; } 线程1,线程2同时运行,线程2退出之后,线程1会不会有可能因为缓存等原因,一直死循环? 真实的世界 第一个坑