下面可是我亲手敲打的。。。。肩膀都酸了。。。本可以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); } } }