Java教程

Java中 Volatile关键字

Volatile关键字用于通过不同的线程修改变量的值。它还用于使类线程安全。这意味着多个线程可以同时使用类的方法和实例,而不会出现任何问题。 volatile关键字可以与原始类型或对象一起使用。
volatile关键字不缓存变量的值,并且始终从主内存中读取变量。 volatile关键字不能与类或方法一起使用。但是,它与变量一起使用。它还保证可见性和顺序。它可以防止编译器对代码进行重新排序。
特定设备寄存器的内容可以随时更改,因此您需要volatile关键字,以确保编译器不会优化此类访问。

示例

class Test
{
    static int var=5;
}
在上面的示例中,假定两个线程在同一类上工作。两个线程都在不同的处理器上运行,其中每个线程都有其本地var副本。如果有任何线程修改其值,则更改将不会反映在主内存中的原始线程中。导致数据不一致,因为另一个线程不知道修改后的值。
class Test
{
    static volatile int var =5;
}
在上面的示例中,静态变量是在所有对象之间共享的类成员。主存储器中只有一个副本。 volatile变量的值永远不会存储在缓存中。所有读写操作都将在主内存中进行。

何时使用它?

如果要自动读写long和double变量,可以使用volatile变量。 它可以用作Java中实现同步的另一种方法。 完成读取操作后,所有读取器线程将看到volatile变量的更新值。如果您不使用volatile关键字,则不同的阅读器线程可能会看到不同的值。 它用于通知编译器多个线程将访问特定的语句。这样可以防止编译器进行任何重新排序或任何优化。 如果不使用易失性变量,编译器可以对代码重新排序,可以自由地写入易失性变量的缓存值,而不用从主存储器中读取。

重要要点

您可以将volatile关键字与变量一起使用。在类和方法中使用volatile关键字是非法的。 它保证volatile变量的值始终从主内存中读取,而不是从本地线程缓存中读取。 如果您声明变量为volatile,则读写是原子的 它降低了内存一致性错误的风险。 任何对Java中的volatile变量的写操作都会在与该变量连续读取的关系建立之前发生。 volatile变量始终对其他线程可见。 作为对象引用的volatile变量可以为null。 在多个线程之间不共享变量时,不需要在该变量中使用volatile关键字。

同步与volatile关键字之间的区别

Volatile关键字不能替代synced关键字,但是在某些情况下可以用作替代。有以下区别如下:
Volatile关键字 Synchronization关键字
Volatile关键字是字段修饰符。 Synchronized关键字修改代码块和方法。
在发生波动的情况下,无法阻止线程等待。 在同步的情况下可以阻止线程等待。
它提高了线程性能。 同步方法会降低线程性能。
它一次在线程内存和主内存之间同步一个变量的值。 它在线程内存和主内存之间同步所有变量的值。
易失性字段不受编译器优化的影响。 同步需要进行编译器优化。

易失关键字示例

在下面的示例中,我们定义了一个增加计数器值的类。当线程开始执行时,VolatileThread.java中的run()方法将获取更新值和旧值。在主类中,我们定义线程的数组。
VolatileData.java
public class VolatileData{
    private volatile int counter = 0;
    public int getCounter(){
        return counter;
    }
    public void increaseCounter() {
        ++counter;
    //increases the value of counter by 1
    }
}
VolatileThread.java
VolatileThread.java
public class VolatileThread extends Thread{
    private final VolatileData data;
    public VolatileThread(VolatileData data) {
        this.data = data;
    }
    @Override
public void run(){
        int oldValue = data.getCounter();
        System.out.println("[Thread " + Thread.currentThread().getId() + "]: Old value = " + oldValue);
        data.increaseCounter();
        int newValue = data.getCounter();
        System.out.println("[Thread " + Thread.currentThread().getId() + "]: new value = " + newValue);
    }
}
VolatileMain.java
public class VolatileMain{
    private final static int noOfThreads = 2;
    public static void main(String[] args) throws InterruptedException{
        VolatileData volatileData = new VolatileData();
        //object of VolatileData class
        Thread[] threads = new Thread[noOfThreads];
        //creating Thread array
        for(int i = 0;i <noOfThreads;++i)
            threads[i] = new VolatileThread(volatileData);
            for(int i = 0;i <noOfThreads;++i)
                threads[i].start();
            //starts all reader threads
            for(int i = 0;i <noOfThreads;++i)
                threads[i].join();
                //wait for all threads
    }
}
输出:
[Thread 9]: Old value = 0
[Thread 9]: new value = 1
[Thread 10]: Old value = 1
[Thread 10]: new value = 2

昵称: 邮箱:
Copyright © 2022 立地货 All Rights Reserved.
备案号:京ICP备14037608号-4