Java中的synchronized、Object.wait()、Object.notify()/notifyAll()原理

来源:互联网 发布:淘宝投诉号码 编辑:程序博客网 时间:2024/05/22 07:55
 

http://www.zeroup.org/javas-synchronized-object-wait-object-notify-notifyall-works.html

synchronized与互斥锁mutex

synchronized用来锁定某个对象,体现的是标准的互斥锁mutex的机制,synchronized代码块的开始即是lock该mutex,代码块的结束即是unlock。

Object.wait()与条件变量

Object.wait()在使用时通常要判断是否满足某个条件,不满足某个外部条件cond时调用wait(),来让线程阻塞同时释放被synchronized锁定的mutex;从这个过程看来Object.wait()实际上是起到条件变量的作用,wait()内部实际上先将synchronized锁定的锁释放,之后将当前线程阻塞在某个内置的条件condition上(注意:此condition为内置的,与外部判断的条件cond并非同一个,外部的cond需要程序员根据程序逻辑来判断改变,而这个condition只能被Object.notify()/notifyAll()改变),直到内置条件condition被Object.notify()/notifyAll()修改时才会重新锁定该mutex,继续执行wait()后的代码。

Object.notify()/notifyAll()与条件变量

Object.notify()/notifyAll()实际上只起到一个sinal内置条件变量的作用,调用Object.notify()/notifyAll()之后,这个时候其他处于wait()中的线程所等待的内置条件变量已经满足,但是由于wait()中仍然需要lock mutex,而在Object.notify()/notifyAll()中没有把mutex释放掉,故阻塞在wait()处的线程继续等待,但等待的条件不再是内置条件变量而是锁mutex;直到synchronized代码块结束时,由于会自动释放被synchronized锁定的mutex,故此时所有在wait()中等待mutex的线程开始竞争mutex,得到该mutex的会继续执行,否则继续等待mutex。

相关代码

1
2
3
4
5
6
7
    synchronized (obj) {// 此处相当于mutex=obj,lock(mutex)
    while (!cond) {// 判断外部条件cond,不满足时让线程wait();
        obj.wait();
    }
    // .....执行满足条件cond时的逻辑过程
    obj.notifyAll();// 更改内置条件condition
    }// 此处相当于mutex=obj,unlock(mutex)

obj.wait()内部实现(伪代码):

1
2
3
4
5
    wait() {
    unlock(mutex);//解锁mutex
    wait_condition(condition);//等待内置条件变量condition
    lock(mutex);//竞争锁
    }

obj.notify()/notifyAll()内部实现(伪代码):

1
2
3
    obj.notify()/notifyAll(){
    condition=true;//只起到把内置条件变量置为true的作用
    }

注意:该代码中之所以用while循环判断该外部条件cond,是因为,第一次Object.notify()/notifyAll()被调用之后,所有线程所等待的内部条件condition都已经满足。此时所有线程竞争mutex,而mutex只会被其中一个线程获得,其余线程继续等待在mutex上。当获得mutex的那个线程执行结束时,所有线程又会竞争mutex,此时,某个线程因为获得了mutex而继续执行。 但这个过程中该线程并没有判断外部条件cond是否成立。 也许在第一次获得mutex的线程中已经将外部条件cond改变为false,而当前获得mutex的线程没有判断cond是否为true而直接执行了后续的代码,相当于通过漏洞执行了后续的代码,必然导致程序逻辑的错误。故,必须用while判断外部条件。同时,由此得出,wait和notify所等待和改变的内置条件变量condition一定在obj对象中,只有这样所有被锁定在obj上的线程才能共享该condition。故可以做这样的推断:
被synchronized锁定的mutex为mutex =obj.mutex;
被wait和notify共享的内置条件变量condition = obj.condition;

总结

在使用synchronized、Object.wait()、Object.notify()/notifyAll()实现线程同步时,用到了两种机制:线程互斥锁mutex和条件变量condition。