JVM对多线程的支持有两种:
1 互斥:通过对象锁来实现
2 协同:通过Object类的wait,notify,notifyAll方法来实现
关于互斥:
我们讲过,在JVM的运行时数据区,方法区和堆区是被多有线程共享的,java栈和PC寄存器是线程独占的。因此我们需要考虑多线程访问方法区和堆区时的数据安全问题。 方法区中的共享数据是类变量,堆区的共享数据是对象变量。(不懂看类的生命周期和对象的生命周期相关博客)
Java虚拟机会自动的为每一个类或者对象都关联一个锁,前者叫类锁,后者叫对象锁。可红色部分明明说互斥是通过对象锁来完成的,难道说错了?
这里就需要了解,在jvm中真的是只有对象锁的。逻辑上说的类锁是通过为类的Class对象加锁形成的。在java中,我们常常会使用几种写代码的方式:
第一种 (同步方法) private synchronized void xxxXxx(){...}; 第二种(同步块) private void xxxXxx(){ synchronized(this){ ...} } 第三种 (静态同步方法) private static synchronized void xxxXxx(){...}; 第四种(静态同步块) private static void xxxXxx(){ synchronized(A.class){ ...} } 第五种:(私有锁) private Object myLock=new Object();
上面的第一种形式,当一个类对象a调用xxxXxx方法时,会获得该对象a的对象锁,从而保证方法被同步执行。第二种形式this指代当前方法,因此执行代码块时也会获得a的对象锁。第三种形式,当类A执行他的xxxXxx方法时,会获得类A的类锁,即类A的Class对象的对象锁。第四种形式,当执行代码块的时候,会获得类A的类锁。第五种形式,利用对象myLock的对象锁。
因此,在原理上,第一种和第二种是相同的,第三种和第四种是相同的。
由此可见,在JVM中,锁都是以对象锁的形式存在的。 当JVM在生成对象的时候,会自动的为每一个对象关联一个锁。这就保证了每个对象有对象锁,而每个类有类锁。
关于协作:
JVM对线程协作的支持是通过Object类的wait,notify,notifyAll方法来实现的。
wait方法:使持有当前对象锁的线程释放该对象锁,并进入等待区
notify方法:唤醒一个正在等待当前对象锁的线程
notifyAll方法:唤醒所有正在等待当前对象锁的线程
从对这些方法的功能描述应该容易理解,这些方法必须在同步方法或者同步代码块中被调用。