1 什么是java object monitor
每个java对象头中都有锁状态位标记。java中在使用synchronize同步的时候,肯定是涉及到某个对象的锁。因此,在考虑同步的时候,首先要想到是同步的是哪个对象的锁。
在java字节码上,获取了某个对象的锁之后,进入时会调用monitorenter指令,在退出时会调用monitorexit指令。
可见,java object monitor是对java对象的锁的一种抽象。它和java对象是一对一的关系的。
在java中,通过java object monitor使得锁是和其保护的对象一一对应的。
2 关于synchronized关键字
它可以用来修饰普通方法,静态方法和修饰代码段。
修饰普通方法的时候,使用的monitor就是类对应的对象的锁。
修饰代码段的时候,使用的monitor也是类对象的对象的锁。
而修饰静态方法时,使用的monitor是类的class对象的锁,这样的monitor只有一个。
具体可以参考下面的博文:
http://www.cnblogs.com/paddix/p/5367116.html
3 为什么“只有拥有该对象的monitor的线程才可以调用该对象的wait()、notify()和notifyAll()方法”?
因为wait()、notify()和notifyAll()是object monitor提供的函数,在语义上,没有拥有该monitor的线程是不能调用它们的。java通过抛出异常来
保证程序在用法上满足这个语义。
4 为什么“wait/notify”方法必须要在synchronized的方法或者段中调用呢?
因为只有进入了synchronized方法或者方法段中的线程才拥有了该锁对象,只有拥有了该锁对象才能调用该锁对象的wait和notify方法。
5 下面的代码在wait之后呢?被唤醒之后,是接着wait后面的执行吗?
synchronized (object) {
while (<condition does not hold>)
object.wait();
// perform actions to condition
}
是的,被唤醒之后,它又重新获取了该锁之后,就会接着wait后面的执行。
例子:
public class Test {
public static Object object = new Object();
public static void main(String[] args) {
Thread1 thread1 = new Thread1();
Thread2 thread2 = new Thread2();
thread1.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.start();
}
static class Thread1 extends Thread{
@Override
public void run() {
synchronized (object) {
try {
object.wait();
} catch (InterruptedException e) {
}
System.out.println("线程"+Thread.currentThread().getName()+"获取到了锁");
}
}
}
static class Thread2 extends Thread{
@Override
public void run() {
synchronized (object) {
object.notify();
System.out.println("线程"+Thread.currentThread().getName()+"调用了object.notify()");
System.out.println("线程"+Thread.currentThread().getName()+"释放了锁");
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("同步块外的逻辑"+Thread.currentThread().getName());
}
}
}
先打印Thread1中要打印的内容,然后再打印Thread2中要打印的内容。
6 notify()和notifyAll()的使用
第一:调用 notify() 方法导致解除阻塞的线程是从因调用该对象的 wait() 方法而阻塞的线程中随机选取的,我们无法预料哪一个线程
将会被选择,所以编程时要特别小心,避免因这种不确定性而产生问题。
第二:除了 notify(),还有一个方法 notifyAll() 也可起到类似作用,唯一的区别在于,调用 notifyAll() 方法将把因调用该对象的
wait() 方法而阻塞的所有线程一次性全部解除阻塞。当然,只有获得锁的那一个线程才能进入可执行状态。