Java教程

Java内存模型中的volatile和synchronized关键字

本文主要是介绍Java内存模型中的volatile和synchronized关键字,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

volatile关键字:

- `volatile`关键字有两个作用:保证可见性和禁止指令重排序。
- 保证可见性:当一个变量被`volatile`修饰时,它会被保证对所有线程的可见性。也就是说,当一个线程修改了这个变量的值,其他线程可以立即看到修改后的值,而不是使用缓存中的旧值。
- 禁止指令重排序:当代码执行时,JVM为了优化,可能会对指令进行重排序。而有时候,这种重排序可能会导致程序出现错误。当一个变量被`volatile`修饰后,JVM会禁止对其进行指令重排序,从而保证程序的正确性。
- 举例:假设有两个线程,一个线程负责写入变量,另一个线程负责读取变量。如果没有使用`volatile`关键字修饰变量,那么读取线程可能会一直读取缓存中的旧值,而写入线程可能会将新值一直保存在CPU的寄存器中,不会及时刷回内存。但是,如果使用`volatile`关键字修饰变量,那么写入线程修改变量的值后,会立即刷回到内存,而读取线程读取变量时,会从内存中获取最新的值,从而保证了可见性。

synchronized关键字:

- `synchronized`关键字用于实现多线程之间的同步。通过加锁和释放锁的机制,确保在同一时间只有一个线程可以访问被`Synchronized`修饰的方法或代码块。
- 根据使用方式的不同,可以分成两种情况:
    - 对象锁:当`synchronized`修饰一个普通方法或代码块时,使用的是对象级别的锁。在同一时间内,只有一个线程可以访问这个对象的被`Synchronized`修饰的方法或代码块。
    - 类锁:当`synchronized`修饰一个静态方法或代码块时,使用的是类级别的锁。在同一时间内,只有一个线程可以访问这个类的被`Synchronized`修饰的静态方法或代码块。
- 举例:假设有一个共享资源`counter`和两个线程同时对其进行操作。如果不使用`synchronized`关键字进行同步,可能会导致并发问题,如数据不一致。但是,如果使用`Synchronized`关键字对操作`counter`的方法或代码块进行同步,可以确保在任意时间点只有一个线程在操作`counter`,从而避免了并发问题。

例如:

public class Counter {
    private int counter = 0;
  
    public synchronized void increment() {
        counter++;
    }
  
    public synchronized void decrement() {
        counter--;
    }
  
    public int getCounter() {
        return counter;
    }
}

public class Main {
    public static void main(String[] args) {
        Counter counter = new Counter();
  
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                counter.increment();
            }
        });
  
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                counter.decrement();
            }
        });
  
        t1.start();
        t2.start();
  
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
  
        System.out.println(counter.getCounter()); // 输出结果为0
    }
}

这个例子中,counter是一个共享资源,初始值为0。线程t1负责递增counter的值,线程t2负责递减counter的值。通过synchronized关键字对increment()decrement()方法进行同步,保证在任意时间点只有一个线程可以访问这两个方法,避免了并发问题。最终输出结果为0。

这篇关于Java内存模型中的volatile和synchronized关键字的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!