Java多线程编程(5)-volatile和synchronized比较
2015-04-02 15:48
609 查看
volatile和synchronized比较
1. volatile只能保证共享变量的可见性,不能保证共享变量操作的原子性;volatile不需要锁,比synchronized轻量级,不会阻塞线程。2.从内存可见性来说,volatile读相当于对共享变量加锁,写相当于对共享变量解锁。
3.synchronized既可以保证共享变量的可见性,也可以保证原子性。
4.除了用synchronized,也可以用 java.util.concurrent.locks.Lock。
几个概念
1.共享变量: 一个变量如果在多个线程中都存有副本,那么这个变量就是这几个线程的共享变量。共享变量的访问权限用private修饰。2.可见性:一个线程对共享变量值的修改,能够及时地被其它线程看到。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存,所以对其他线程是可见的。比如 volatile int a = 0;之后有一个操作 a++;这个变量a具有可见性,但是a++ 依然是一个非原子操作,依然可能导致线程不安全。
3.原子性:不可分割的操作,可以保证线程运行的安全。
volatile导致线程不安全的示例
运行程序几次程序,可以看出volatileNumber最终可能并不是200,线程不安全。public class VolatileExample { // 线程共享变量须定义成private访问权限,volatile不能保证原子性 private volatile int volatileNumber = 0; public static void main(String[] args) { final VolatileExample ve = new VolatileExample(); for (int i = 0; i < 200; i++) { new Thread(new Runnable() { @Override public void run() { ve.increase(); } }).start(); } // 如果还有子线程在运行,主线程就让出资源。 // 等所有的子线程运行结束,主线程继续执行 while (Thread.activeCount() > 1) { Thread.yield(); } // 经过500个循环,发现volatileNumber输出结果可能不是200 System.out.println("num is:\t" + ve.getVolatileNumber()); } /** * 对volatileNumber进行++操作 */ public void increase() { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } this.volatileNumber++; } public int getVolatileNumber() { return this.volatileNumber; }
synchronized可以保证原子性
public class SynExample { // 线程共享变量须定义成private访问权限 private int synNumber = 0; public static void main(String[] args) { final SynExample example = new VolatileExample(); for (int i = 0; i < 200; i++) { new Thread(new Runnable() { @Override public void run() { example.increaseSynNumber(); } }).start(); } // 如果还有子线程在运行,主线程就让出资源。 // 等所有的子线程运行结束,主线程继续执行 while (Thread.activeCount() > 1) { Thread.yield(); } // 使用synchronized关键字后,是原子操作,synNumber 输出结果一定200 System.out.println("synNumber is:\t" + example.getSynNumber()); } /** * 对synNumber进行++操作,使用synchronized */ public void increaseSynNumber() { synchronized (this) { this.synNumber++; } } public int getSynNumber() { return this.synNumber; } }
java.util.concurrent.locks.Lock保证原子性
java.util.concurrent.locks.Lock封装了synchronized,提供了更丰富的功能。public class LockExample { private int lockNumber = 0; public static void main(String[] args) { final LockExample example= new LockExample(); for (int i = 0; i < 200; i++) { new Thread(new Runnable() { @Override public void run() { example.increaseLockNumber(); } }).start(); } // 如果还有子线程在运行,主线程就让出资源。 // 等所有的子线程运行结束,主线程继续执行 while (Thread.activeCount() > 1) { Thread.yield(); } // 发现使用Lock后,是原子操作,lockNumber输出结果一定200 System.out.println("locknumber is:\t" + example.getLockNumber()); } /** * 对lockNumber进行++操作,使用lock */ public void increaseLockNumber() { lock.lock(); try { this.lockNumber++; } finally { lock.unlock(); } } public int getLockNumber() { return this.lockNumber; } }
相关文章推荐
- Java 多线程之 synchronized 和 volatile 的比较
- JAVA多线程同步:volatile,synchronized,Atomic... 比较
- Java多线程之synchronized和volatile的比较
- Java实现内存可见性的两种方法比较:synchronized 和 Volatile以及涉及到锁的剖析
- 【转】Java多线程编程中易混淆的3个关键字( volatile、ThreadLocal、synchronized)总结
- JAVA多线程之volatile 与 synchronized 的比较
- JAVA多线程之volatile 与 synchronized 的比较
- Java之多线程内存可见性_3(synchronized和volatile比较)
- Java 多线程之 synchronized 和 volatile 的比较
- JAVA多线程之volatile 与 synchronized 的比较
- JAVA Synchronized (三) volatile 与 synchronized 的比较
- Java线程中的volatile和synchronized的比较
- JAVA多线程之volatile 与 synchronized 的比较
- Java多线程编程-(13)-从volatile和synchronized的底层实现原理看Java虚拟机对锁优化所做的努力
- Java 多线程之 synchronized 和 volatile 的比较
- JAVA多线程之volatile 与 synchronized 的比较
- Java中volatile的作用以及它和synchronized的比较
- Java多线程之内存可见性——synchronized与volatile比较
- Java线程(二):线程同步synchronized和volatile
- Java线程(二):线程同步synchronized和volatile