1
2
3
4
int i=0;
public int getNextId() {
return i++;
}

执行步骤:

  1. JVM首先在main memory(JVM堆),分配给i一个内存存储场所(常量池),并赋值为0
  2. 线程启动后,自动分配一片working memory区(通常是操作数栈),当线程执行到return i++时,JVM中并不是简单的一个步骤完成的。

i++的动作,在JVM中分为:装载i、读取i、进行i+1操作、存储i及写入i,五个步骤:

  • 装载i

    • 线程发起一个装载i的请求给JVM线程执行引擎,引擎接收请求后,会向main memory发起一个read i指令
    • 当read i执行完毕后一段时间,线程会将i的值从main memory区复制到working memory区中
  • 读取i

    • 此步负责从main memory中读取 i
  • 进行i + 1

    • 线程执行
  • 存储i

    • 将i+1的值,赋给i,然后存储到working memory中
  • 写入i

    • 一段时间后,会将i的值写入main memory

上述步骤,由于不是原子性操作的问题,在多线程执行时,会出现问题

JVM把对于working memory的操作分为:

  • use

    • 将变量值从work memory复制到线程执行引擎中
  • assign

    • 将变量值复制到线程的work memory中
  • load

    • 将main memory中read到的值,复制到work memory
  • store

    • 将变量的值从work memory复制到main memory中,并等待main memory通过write动作写入此值
  • lock

    • 同步操作main memory,给对象加锁
  • unlock

    • 同步操作main memory,释放对象锁

以上操作由线程执行

JVM对于main memory的操作分为:

  • read

    • 从main memory中读取变量的值
  • write

    • 将work memory的值写入main memory中
  • lock

  • unlock

    以上操作由线程执行引擎执行

JVM保证一下操作是顺序执行的:

  1. 同一个线程上的操作一定是顺序执行的
  2. 对于main memory上的同一个变量的操作一定是顺序执行的,也就是不可能两个请求同时读取变量值
  3. 对于加锁的main memory上的对象操作,一定是顺序执行的,也就是两个以上加了lock锁的操作,同时肯定只有一个是在执行的

采用synchronized改造上边代码

1
2
3
public synchronized int getNextId() {
return i++;
}