说明:由于大家都对Object的monitor依赖,或多或少的相互影响
一、synchronized 原理:
多线程的情况下,每个线程共享进程的资源,为了保证数据的一致性,java引入了synchronized。
三种方式:1.synchronized method 2.synchronized code block 3.static synchronized method
1.synchronized method:
public class SyncObj {
public synchronized void method() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method run");
}
public synchronized void method1() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method1 run");
}
}
此时
public static void main(String[] args) {
final SyncObj obj=new SyncObj();
new Thread(){
@Override
public void run() {
obj.method();
}
}.start();
new Thread(){
@Override
public void run() {
obj.method1();
}
}.start();
}
能看到method 执行的时候,method1进入了等待,这是因为synchronized method是进行了对象锁,把当前对象的monitor上了锁,每个对象都有一个monitor的锁,初始状态是0,执行完synchronized 值变成1.
这时候,其他线程访问这个代码时,
先检测这个对象的monitor是否是0:
1.如果是0,就直接占用,并且把monitor改成1
2.如果这是这个值是1,线程等待,直到其他占用者释放这个锁。
2.synchronized code block 同理。
3.static synchronized method 由于是静态方法,锁住的是这个类。所有对于这个类的静态同步方法,都会进行上面的竞争机制不在局限于同一个对象。
二、wait/notify
Object 类的对象有这么几个native方法:
//wait
/**
* This method should only be called by a thread that is the owner
* of this object's monitor.
*/
public final native void wait() throws InterruptedException;
public final native void wait(long millis, int nanos) throws InterruptedException;
public final void wait(long millis) throws InterruptedException {
wait(millis, 0);
}
//notify
/**
* Wakes up a single thread that is waiting on this object's
* monitor. If any threads are waiting on this object, one of them
* is chosen to be awakened. The choice is arbitrary and occurs at
* the discretion of the implementation. A thread waits on an object's
* monitor by calling one of the {@code wait} methods.
*/
public final native void notify();
/**
* Wakes up all threads that are waiting on this object's monitor. A
* thread waits on an object's monitor by calling one of the
* {@code wait} methods.
*/
public final native void notifyAll();
wait()/notify() 需要获得monitor的线程才可以执行,详见Object的源码注解
三、wait/notify的纠缠
/**
* This method should only be called by a thread that is the owner
* of this object's monitor.
*/
纠缠1
执行wait必须获得monitor,而第一部分讲到synchronized method 就获得了这个monitor。所以要执行wait方法,必须和synchronized混合使用,否则会抛出IllegalMonitorStateException 异常
public synchronized void method() {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method run");
}
纠缠2
这个时候执行开启多线程执行obj的method方法。会发现:
1.这些线程都进入了wait状态。
不知道聪明的你是否发现了发生了疑惑甚至质疑:
synchronized method 表明此方法明明需要获得monitor才可以执行,既然线程1已经获取了monitor并且进入等待状态,在没有其他线程唤醒他的情况下,还是在同步代码块内部,这个时候应该其他线程都处于阻塞状态。