首先我们要了解java代码先要被执行,首先是被转成一个字节码文件组成的class类。

jvm的内存结构分为:堆,本地方法栈,栈,方法区。

线程和共享数据

每一个线程都享有一个栈内存,其中包括局部变量,线程调用的方法参数和返回值,其他线程无法读取到线程栈的数据。栈中数据只包括对象的引用,所以在jvm无法保证栈重存储的是真实的对象。真的的对象要保存到堆中去。

在jvm中堆的线程是共享的。堆中只有对象,没有其他东西,无法保证基本数据类型的对象的引用。栈的堆分工明确,对象的引用也是对象的一部分。

除了堆和栈,还有一部分数据可能保存早方法区中,就不如静态变量。方法区和栈类似。只包含对象的引用和基本数据类型,和栈不同的是方法区中静态变量能被所以线程访问到。

对象和类的锁

如上述所说,jvm中由两个区域是被线程共享的。

如果多个线程方位同一个对象或静态变量时,就需要被管控,否则就会出现不可预期的结果

为了协调多线程之间的数据共享,虚拟机给了每一个对象一把锁,在同一时刻,只有一个线程可以用这个对象。如果一个线程想要获取类和对象的锁锁,就要询问虚拟机,当一个线程想一个对象申请锁之后,也许很快虚拟机就会把锁分配给线程,同时这个线程肯能永远都无法获取到锁。当线程不需要锁时,就释放掉锁,这时虚拟机再把对象分配给其他线程

类锁是通过对象锁实现的,当虚拟机加载一个类时,会为这个虚拟机实例化一个class对象,当你锁着一个类时,往往锁住的是对应的class对象

监视器(Monitors)

监视器和锁同时被jvm使用,监视器的主要工作就是监视一块代码,保证在同一时刻只有一个线程访问

每个监视器都与一个对象管理。当线程执行到监视器下的代码块的第一个指令时,线程必须获取被引用对象的锁定。在线程获取锁之前他是无法执行这段代码的,一旦获取锁,线程就进入被保护状态,线程变可以被保护,代码开始执行。

当线程离开代码块时,无论何时离开,都要释放锁。

多次加锁

同一个线程可以堆同一个对象进行多次加锁,每个对象维护者被加锁次数的计数器。未被锁定时为0,当一个线程被锁定是,自增为1,当一个对象再次获取锁时继续自增。当一个线程被释放锁时,计数器自减,当计数器为0时,就释放锁。

同步

在java中,当有多个线程访问同一数据时,由一种协调方法叫做同步。java语言中提供了两种方式来使线程同步访问数据:同步方法,同步代码块。