庆云网站建设,万网速成网站有哪些 功能,平面设计教程网站,自己如何在网上做网站volatile和synchronized都是Java中用于控制并发的关键字#xff0c;但是它们的使用场景和原理是不同的。
volatile关键字#xff1a; 特点#xff1a;volatile关键字主要有两个特性#xff1a;保证变量的可见性和防止指令重排。当一个共享变量被volatile修饰时#xff0c…volatile和synchronized都是Java中用于控制并发的关键字但是它们的使用场景和原理是不同的。
volatile关键字 特点volatile关键字主要有两个特性保证变量的可见性和防止指令重排。当一个共享变量被volatile修饰时它会保证修改的值会立即被更新到主存当有其他线程需要读取时它会去内存中读取新值。而普通的共享变量不能保证可见性因为线程间的共享变量值存在于主存而每个线程都有自己的工作内存线程间通信需要通过主存来完成。这可能导致一个线程在主存中修改了一个变量的值另一个线程还继续使用它在工作内存中的变量值造成数据的不一致。另外volatile关键字可以防止指令重排。编译器优化的时候不能够将其后面的代码排到其前面来执行。当要对一个volatile变量进行写操作时JMM会先将操作执行然后再执行volatile写操作即不会进行指令重排。优点volatile相对于synchronized是一种较为轻量级的同步策略性能开销相对较小线程访问volatile变量不会被阻塞。缺点volatile无法保证复合操作的原子性。例如count操作实际上是分为三步执行的读取count的值对count加1将新值写回。适用场景当对变量的写入依赖于当前值例如使用该变量做判断或者写入的值与当前值无关时可以使用volatile。例如一个布尔标记位。不适用场景当需要对多个操作进行原子性保证或者需要对某些方法或者某些代码块进行同步控制的时候不能够使用volatile。
public class VolatileExample {private volatile int counter 0;public void incrementCounter() {counter;}public int getCounter() {return counter;}public static void main(String[] args) throws InterruptedException {VolatileExample example new VolatileExample();Thread thread1 new Thread(() - {for (int i 0; i 1000; i) {example.incrementCounter();}});Thread thread2 new Thread(() - {for (int i 0; i 1000; i) {example.incrementCounter();}});thread1.start();thread2.start();thread1.join();thread2.join();System.out.println(Counter: example.getCounter()); // 输出结果可能小于2000}
}
在上述示例中尽管使用了volatile关键字但是incrementCounter()方法并不是线程安全的因为counter操作不是原子性的所以最后输出的结果可能小于2000。
synchronized关键字 特点synchronized关键字可以保证代码块或者方法的原子性即在同一时刻只有一个线程可以执行synchronized修饰的代码块或者方法。另外它还可以保证变量的可见性和防止指令重排。当一个线程进入synchronized代码块或者方法时其他线程不能进入只有当该线程退出后其他线程才能进入这就保证了原子性。当一个线程退出synchronized代码块或者方法时它对共享变量的修改会立即写入主存当其他线程进入后它会从主存读取共享变量的新值这就保证了可见性。另外编译器和处理器在执行synchronized代码块或者方法时不会进行指令重排。优点synchronized关键字可以保证代码块或者方法的原子性可以解决多个线程同时访问共享资源导致的线程安全问题。缺点synchronized关键字的性能开销较大当一个线程进入synchronized代码块或者方法时其他线程会被阻塞可能导致线程的阻塞和唤醒带来大量的性能开销。适用场景当需要对多个操作进行原子性保证或者需要对某些方法或者某些代码块进行同步控制的时候可以使用synchronized。不适用场景当只需要保证变量的可见性而不需要保证原子性或者对性能有较高要求的时候不适合使用synchronized。
public class SynchronizedExample {private int counter 0;public synchronized void incrementCounter() {counter;}public int getCounter() {return counter;}public static void main(String[] args) throws InterruptedException {SynchronizedExample example new SynchronizedExample();Thread thread1 new Thread(() - {for (int i 0; i 1000; i) {example.incrementCounter();}});Thread thread2 new Thread(() - {for (int i 0; i 1000; i) {example.incrementCounter();}});thread1.start();thread2.start();thread1.join();thread2.join();System.out.println(Counter: example.getCounter()); // 输出结果为2000}
}
在上述示例中使用了synchronized关键字incrementCounter()方法是线程安全的因为synchronized关键字保证了counter操作的原子性所以最后输出的结果为2000。