下面可是我亲手敲打的。。。。肩膀都酸了。。。本可以copy的。。。哎,但为了加深印象。。。顺便练练打字。。。
经过网上查证,wait()允许我们将线程置入睡眠状态,同时又积极的等待条件发生改变,而且只有当一个notify()或notifyAll()发生改变时,线程才会被唤醒,并检查条件是否有变,这里就只用while判断。不能用if
wait()允许我们将线程置入睡眠状态,也就是说,wait也是让当前线程阻塞的,这一点和sleep或者suspend 是相同的,那和sleep,suspend有什么区别呢?
区别1;wait 是Object类中的方法,sleep和suspend 是Thread 类中的方法
区别2在于wait 同时又积极的等待条件发生改变。。这点很关键,sleep和suspend 无法做到。因为我们有时候需要通过同步(synchronized)的帮助来防止线程之间的冲突,而一旦使用同步,就要锁定对象,也就是获取对象锁,其他要使用该对象锁的线程都只能排队等着,等到同步方法或者同步块里的程序全部执行完才有机会。在同步方法和同步块,
无论sleep还是suspend 都不可能自己被调用的时候解除锁定,他们都霸占着正在使用的对象锁不放。。。sleep很贪婪哦
而wait 却可以,它可以让同步方法或同步块暂时放弃对象锁,而将它暂时让给其他需要对象锁的人(这里是指程序块,或线程块)用,这意味着可在执行wait 期间调用线程对象中的其他同步方法。。。在其他情况下,这是不可能的。
但是注意我前面说的,只是暂时放弃对象锁,暂时给其他线程用,我wait还是要把这个对象锁收回来的。。。。怎么收回来??啥时候收回来呢??
第一种方法,限定借出去的时间,在wait 中设置参数,比如wait(1000),以毫秒为单位,就是说只借你一秒钟,然后就收回来
第二种方法,让借出去的人通知我,他用完了,就还给我了。
那么别人怎么通知我呢??相信大家都可以想到了,notify()。对,就是它。也只有在一个notify 或notifAll 发生变化时,线程才会被唤醒。。。啊啊啊,终于醒了
现在摆一个代码:生产者与消费者。。。。相当经典的面试题
package heng.java.Thread2;
public class MoreThread {
public static void main(String[] args) {
SyncStack ss = new SyncStack();
Producer p = new Producer(ss);
Consumer c = new Consumer(ss);
new Thread(p).start();
new Thread(c).start();
}
}
class WoTou {
int id;
WoTou(int id){
this.id = id;
}
public String toString(){
return "WoTou:"+id;
}
}
class SyncStack {
int index = 0;
WoTou []arrWT = new WoTou[6];
public synchronized void push(WoTou wt){
while(index == arrWT.length){
try {
//当wait时,将不再拥有锁,只能等到notify,才能再次拥有锁,这是和sleep最大的区别,sleep即使睡着,也依然拥有锁
this.wait();//(只有锁住时,才能wait)当前的,正在我这个对象访问的线程wait。
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();//让消费者赶紧消费
arrWT[index] = wt;
index ++;
}
public synchronized WoTou pop(){
while(index == 0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.notify();
index --;
return arrWT[index];
}
}
class Producer implements Runnable {
SyncStack ss = null;
Producer (SyncStack ss) {//要有个筐的引用
this.ss = ss;
}
public void run(){
for(int i=0; i<20; i++){
WoTou wt = new WoTou(i);
ss.push(wt);
System.out.println("生产了:"+wt);
try {
Thread.sleep((int)(Math.random()*2));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
SyncStack ss = null;
Consumer(SyncStack ss) {//要有个筐的引用
this.ss = ss;
}
public void run(){
for(int i=0; i<20; i++){
WoTou wt = ss.pop();
System.out.println("消费了:"+wt);
try {
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(wt);
}
}
}