java中Lock的默认Condition问题。
Lock 替代了synchronized 方法和语句的使用,Condition 替代了Object 监视器方法(wait、notify和notifyAll)的使用。Lock的原理其实和synchronized是一样的。
java的每个对象都有一个监视器,只能被同一线程拥有(即同一线程可重入),一旦被一个线程获取,那其它线程只能等待。synchronized(obj)意思就是获得obj的监视器,对应于monitorenter,代码块结束时自动释放,相当于monitorexit。
只有获得了对象的监视器,才能执行监视器方法,也就是wait、notify或notifyAll。也就是只有synchronized(this)后才能this.wait或this.notify,不能获得一个对象的监视器而执行另一个对象的监视器方法。
在condictin上await后必须有线程调用condition.signal()。你可以在你的线程上提供2个方法:
class RunA implements Runable {
public void wait1() {
lock.lock();
try {
condition.await();
}finally{
lock.unlock();
}
}
public void continue1() {
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
}
}
本线程调用wait1,另一线程调用continue1通知继续,这跟在Object上的wait与notify是一回事
深入理解wait/notify/notifyAll的作用
notify: 唤醒在监视器对象上等待的单个线程,此时调用该方法的代码继续执行。
notifyAll: 唤醒在监视器对象上等待的所有线程,此时调用该方法的代码继续执行。
第一、为什么会有wait/notify/notifyAll这几个方法?
(1) wait/notify/notifyAll是为了避免轮询(尝试执行)带来的性能损失,这句话是什么意思?看下面的讲解:
为了说清道理,我们用“图书馆借书”这个经典例子来作解释。
在简单的synchrnozed 同步机制下,李四如果想借,先要去图书馆查看书有没有还回来。
李四是个心急的人,他每天都去图书馆查;而张三看书看得慢,过了半个月才把书还回来,
结果李四在这半个月里全都白跑了,浪费了不少交通车费。
而如果使用wait/notify机制,李四就不用白忙了。
他第一次去图书馆时发现书已借走,就回家静静等待(wait);
张三把书还掉后,通知(notify)李四,李四去图书馆拿书即可。整个过程中,李四没有白跑,没浪费钱。
书 ---- 临界资源,需互斥地访问
张三,李四 ---- 两个竞争的线程
坐车去图书馆查书 ---- 轮询
车费 ---- CPU空间
等待 ---- wait
通知下一个借书者 ---- notify
也就是说,若使用简单的synchonized机制实现互斥,会导致线程主动发起轮询,若N次轮询没有成功,就产生了N次的CPU空间浪费;
如果加上了 wait/notify机制,就可以避免这些无谓的轮询,节省CPU的消耗。
(2) wait/notify/notifyAll可以控制线程执行与不执行。
第二、为什么wait/notify/notifyAll方法一定要写在synchronized里面呢?
因为第一点已经说了wait/notify/notifyAll的作用是为了避免轮询带来的性能损失,
而产生轮询的条件是多个线程对同一个资源进行操作。
第三、为什么wait/notify/notifyAll方法定义在Object类里面呢?
因为wait/notify/notifyAll必须写在synchronized里面,而synchronized的对象锁可以是任意对象,
所以wait/notify/notifyAll方法定义在Object类里面呢。
调用wait/notify/notifyAll方法的对象,必须和synchronized()的对象锁一致。
第四、
看一个wait和notify示例:
// 这个示例是不需要flag标记的:
public class Resource {
public String name;
public String sex;
public boolean flag = true;
public static void main(String[] args) {
Resource r = new Resource();
Input in = new Input(r);
Thread t1 = new Thread(in);
Output out = new Output(r);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
class Input implements Runnable {
Resource r;
public Input(Resource r) {
this.r = r;
}
public void run() {
int x = 0;
while (true) {
synchronized (r) {
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
if (x == 0) {
r.name = "谢霆锋";
r.sex = "男人";
} else {
r.name = "张柏芝";
r.sex = "女人";
}
// 注意:调用notify方法后,唤醒了等待的线程。
// 但这里代码继续执行,并不是马上交给其它线程执行,除非cpu时间片结束。
r.notify();
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
x = (x + 1) % 2;
}
}
}
class Output implements Runnable {
Resource r;
public Output(Resource r) {
this.r = r;
}
public void run() {
while (true) {
synchronized (r) {
System.out.println("--------------" + r.name + "是" + r.sex);
r.notify();
try {
r.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
--------------------------------------------------------------
这里要注意,再次强调:
wait/notify/notifyAll方法要放在synchronized里面,除此之外,还要非常非常注意一个重点:
调用wait/notify/notifyAll方法的对象,必须要和synchronized的对象锁是一致的。
如,以下代码是错误的:
class MyThread extends Thread {
public static Object obj = new Object();
public void run() {
synchronized(obj) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.notify();
}
}
}
--------------------------------------------------------------
鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com
图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!