volatile关键字使用总结

volatile关键字使用总结java

VikingBird 发表于2个月前缓存

   

原volatile关键字使用总结多线程

 收藏app

VikingBirdide

 

  • 发表于 2个月前
  •  
  • 阅读 20
  •  
  • 收藏 0
  •  
  • 点赞 0
  •  
  • 评论 0

腾讯云·云上实验室:开发者零门槛,无偿使用真机在线实验!>>>   测试

摘要: 本文主要总结了volatile关键字的使用this

什么是volatile关键字

volatile 关键字在多线程程序中起着很重要的做用。当多个线程操做同一个变量时,每一个线程将拥有对那个变量的本地缓存拷贝,所以,当某一个线程修改了这个变量的值时,实际上修改的是它本地缓存中的变量值,而不是主内存中的变量值,操做这个变量的其余线程并不知道这个变量的值被改变了。为了不这种状况,咱们能够用 valatile 关键字声明这个变量,用 valatile 声明了这个变量以后,变量将不在本地缓存中保存,而在主内存中保存,当有线程修改了它的值之后,它的更新值将被更新到主内存当中,随后,其余线程也能访问更新后的值。当一个变量被声明为 volatile 后,java 内存模型确保全部使用该变量的线程能看到相同的、一致的值。spa

volatile关键字使用

首先,建立 VolatileData 类,代码以下:.net

public class VolatileData {

   //声明为volatile类型
   private volatile int counter = 0;

   /**
    * 返回counter变量的值
    * @return
    */
   public int getCounter() {
       return counter;
   }

   /**
    * 自增counter变量的值
    */
   public void increaseCounter() {
       ++counter;
   }
}

接下来建立 VolatileThread 类,代码以下:线程

public class VolatileThread extends Thread {
   private final VolatileData volatileData;

   public VolatileThread(VolatileData volatileData) {
       this.volatileData = volatileData;
   }

   /**
    * 调用VolatileData类中的两个方法,进行取值和自增操做
    */
   @Override
   public void run() {
       int oldValue = volatileData.getCounter();
       System.out.println("[Thread " + Thread.currentThread().getId() + "]: Old value = " + oldValue);
       volatileData.increaseCounter();
       int newValue = volatileData.getCounter();
       System.out.println("[Thread " + Thread.currentThread().getId() + "]: New value = " + newValue);
   }
 }

最后,建立 VolatileMain 类,对以上程序进行测试,代码以下:

public class VolatileMain {

    private final static int TOTAL_THREADS = 2;

    public static void main(String[] args) throws InterruptedException {
        VolatileData volatileData = new VolatileData();

        Thread[] threads = new Thread[TOTAL_THREADS];
        for(int i = 0; i < TOTAL_THREADS; ++i)
            threads[i] = new VolatileThread(volatileData);

        //开始读取变量值的操做
        for(int i = 0; i < TOTAL_THREADS; ++i)
            threads[i].start();

        //等待全部线程操做终止
        for(int i = 0; i < TOTAL_THREADS; ++i)
            threads[i].join();
    }
}

在 VolatileMain 类中,使用了两个线程来访问 volatile 变量,输出以下:

[Thread 10]: Old value = 0
[Thread 11]: Old value = 0
[Thread 10]: New value = 1
[Thread 11]: New value = 2

从输出能够看到,首先,两个线程都输出了相同的值,接着,在 increaseCounter 方法被调用以后,两个线程都访问和输出了最新的 volatile 变量的值。

happens-before 关系

在使用 volatile 关键字时,不得不提一下 java 内存模型的 happens-before 关系。happens-before 关系是 java 内存模型的一个重要方面。它创建在两个不一样的事件之间,使第一个事件对对象的全部改变均可以被第二个事件看到和反映出。好比当一个线程对 volatile 变量进行写操做后,另外一个线程随后访问该变量,happens-before 关系就创建了。所以,全部对 volatile 变量的改变对其余线程来讲是可见的。

须要注意的

当在程序中使用 volatile 关键字时,咱们必须注意如下几点:

  • volatile 关键字并不能消除原子之间的同步操做的须要,由于内存一致性错误仍然是可能的

  • 使用原子变量比使用 synchronized 同步代码更有效率,可是为了不内存一致性错误,须要做出额外的努力

  • volatile 关键字不能替代 synchronized 同步代码块和方法

相关文章
相关标签/搜索