文章目录[隐藏]
记录
this.notify();
功能:
- 不是唤醒正在执行
this.notify();
的当前线程 - 而是唤醒一个现在正在等待(wait)
this对象
的其它线程 - 如果有多个线程正在等待(wait)
this对象
,通常是唤醒最先等待(wait)this对象
的线程 - 但具体唤醒哪一个,是由系统调度器控制的,程序员无法控制
aa.wait();
- 将执行
aa.wait();
的当前线程转入阻塞状态,让出CPU的控制权 - 释放对
aa
的锁定 - 需要被
try catch
包围,以便发生异常中断也可以使wait等待的线程唤醒。
aa.notify();
- 假设执行
aa.notify();
的当前线程为T1,如果当前时刻有其他线程因为执行了aa.wait()
而陷入阻塞状态,则唤醒其中一个 - 所谓唤醒是令该线程从因wait而陷入阻塞的状态转入就绪状态
- 若在执行
aa.notify();
前没有线程处于wait状态,那么程序也不会出错,相当于唤醒了0个线程
aa.notifyAll()
- 唤醒其它所有的因执行了
aa.wait()
而陷入阻塞状态的线程
在多线程中要测试某个条件的变化,使用if 还是while?
选用while
- 在多线程情况下,在wait过程中cnt可能会被其它线程修改,导致恢复后条件仍然成立
- notify唤醒沉睡的线程后,线程会接着上次的执行继续往下执行。所以在进行条件判断时候,可以先把 wait 语句忽略不计来进行考虑;显然,要确保程序一定要执行,并且要保证程序直到满足一定的条件再执行,要使用while进行等待,直到满足条件才继续往下执行。
以下是简易的生产消费问题:
public class produceConsume { public static void main(String[] args) { SynStack ss = new SynStack(); Producer p = new Producer(ss); Consumer c = new Consumer(ss); Thread t1 = new Thread(p); // 生产线程 Thread t2 = new Thread(c); // 消费线程 t1.start(); t2.start(); } } class SynStack { private char[] data = new char[6]; private int cnt = 0; // 表示数组有效元素个数 public synchronized void push(char ch) { while(cnt == data.length) // 为什么不用if 【在多线程情况下,在wait过程中cnt可能会被其它线程修改,导致恢复后条件仍然成立】 { // 暂停 try { System.out.println("exc push wait"); this.wait(); } catch (Exception e) { e.printStackTrace(); System.out.println("push wait error"); } System.out.println("push resume"); } this.notify(); data[cnt] = ch; cnt++; System.out.printf("生产线程正在生产第%d个产品:%c\n", cnt, ch); } public synchronized char pop() { char ch; while(cnt == 0) { // 暂停 try { // System.out.println("exc pop wait"); this.wait(); } catch (Exception e) { System.out.println("pop error"); } System.out.println("pop resume"); } // System.out.println("awake"); this.notify(); ch = data[cnt - 1]; System.out.printf("消费线程正在消费第%d个产品:%c\n", cnt, ch); --cnt; return ch; } } class Producer implements Runnable { private SynStack ss = null; public Producer(SynStack ss) { this.ss = ss; } public void run() { char ch; for (int i = 0; i < 20; i++) { // try { // Thread.sleep(1000); // } catch (Exception e) { // e.printStackTrace(); // } ch = (char)('a' + i); ss.push(ch); } } } class Consumer implements Runnable { private SynStack ss = null; public Consumer(SynStack ss) { this.ss = ss; } public void run() { for (int i = 0; i < 20; i++) { try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } ss.pop(); } } }