请先关注、点赞、收藏,后阅读。
volatile
关键字有两个作用:保证可见性和禁止指令重排序。volatile
修饰时,它会被保证对所有线程的可见性。也就是说,当一个线程修改了这个变量的值,其他线程可以立即看到修改后的值,而不是使用缓存中的旧值。volatile
修饰后,JVM会禁止对其进行指令重排序,从而保证程序的正确性。volatile
关键字修饰变量,那么读取线程可能会一直读取缓存中的旧值,而写入线程可能会将新值一直保存在CPU的寄存器中,不会及时刷回内存。但是,如果使用volatile
关键字修饰变量,那么写入线程修改变量的值后,会立即刷回到内存,而读取线程读取变量时,会从内存中获取最新的值,从而保证了可见性。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。