【Java基础 005】 线程synchronized和轮询

来源:互联网 发布:郭嘉怎么死的知乎 编辑:程序博客网 时间:2024/06/07 14:50
wait/notify  机制是为了避免轮询带来的性能损失。 
为了说清道理,我们用“图书馆借书”这个经典例子来作解释。 一本书同时只能借给一个人。现在有一本书,图书馆已经把这本书借了张三。 
在简单的synchrnozed 同步机制下,李四如果想借,先要去图书馆查看书有没有还回来。李四是个心急的人,他每天都去图书馆查;而张三看书看得慢,过了半个月才把书还回来,结果李四在这半个月里全都白跑了,浪费了不少交通车费 
而如果使用wait/notify机制,李四就不用白忙了。他第一次去图书馆时发现书已借走,就回家静静等待(wait);张三把书还掉后,通知(notify)李四,李四去图书馆拿书即可。整个过程中,李四没有白跑,没浪费钱。 
回到计算机世界: 
    
       书           --  临界资源,需互斥地访问 
    张三,李四      --  两个竞争的线程 
坐车去图书馆查书   --  轮询 
      车费          --  CPU空间 
      等待          --  wait 
  通知下一个借书者   --  notify 


也就是说,若使用简单的synchonized机制实现互斥,会导致线程主动发起轮询,若N次轮询没有成功,就产生了N次的CPU空间浪费;如果加上了 wait/notify机制,就可以避免这些无谓的轮询,节省CPU的消耗。




例子:
package sun;


public class T3 {
public static void main(String s[]) {
Q q = new Q();
new put(q);
new get(q);
}
}


class Q {
private int n;
private boolean isWait = false;


synchronized void put(int n) {
if (isWait) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.n = n;
System.out.println("put=" + n);
isWait = true;
notify();
}


synchronized void get() {
if (!isWait) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("get=" + n);
isWait = false;
notify();
}
}


class put implements Runnable {
Q q;


public put(Q q) {
this.q = q;
new Thread(this, "Put").start();
}


public void run() {
int i = 0;
while (true) {
q.put(i++);
}
}
}


class get implements Runnable {
Q q;


public get(Q q) {
this.q = q;
new Thread(this, "Get").start();
}


public void run() {
while (true) {
q.get();
}
}
}