Java内存模型(Java Memory Model)描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节!
所有的变量都存储在主内存中每个线程都有自己独立的工作内存,里面保存该线程使用到的变量副本(主内存中该变量的一份拷贝)下面的代码期望运行结果是500!但实际结果几乎都不是!
public class VolatileDemo { private int number = 0; public int getNumber() { return this.number; } public void increase() { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } this.number++; } public static void main(String[] args) { final VolatileDemo volatileDemo = new VolatileDemo(); //启动500个线程,对volatileDemo对象调用increase方法! for(int i = 0; i < 500; i++) { new Thread(new Runnable() { @Override public void run() { volatileDemo.increase(); } }).start(); } //如果有子线程在运行,主线程就让出cpu资源,直到子线程都运行完,主线程再继续执行! while(Thread.activeCount() > 1) { Thread.yield(); } System.out.println("number: " + volatileDemo.getNumber()); } }程序分析:
1 线程A读取number的值。 2 线程B读取number的值 3 线程B执行加1操作 4 线程B写入最新的number值 5 线程A执行加1操作 6 线程A写入最先的number值 结果:两次number++实际只增加了1. 解决方案: 保证number自增操作的原子性: 1 使用synchronized关键字 2 使用ReentrantLock (java.util.concurrent.locks包下) 3 使用AtomicInteger(java.util.concurrent.atomic包下)
public void increase() { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (this) { this.number++; } } private Lock lock = new ReentrantLock(); private int number = 0; public int getNumber() { return this.number; } public void increase() { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } lock.lock(); try { this.number++; } finally { lock.unlock(); } }