awAmount
125 */
126 public synchronized void draw(double drawAmount, int i) {
127 if (!flag) {
128 // 账户中还没人存钱进去,此时当前线程需要等待阻塞
129 try {
130 System.out.println(Thread.currentThread().getName() + " 开始要执行wait操作" + " 执行了wait操作" + " -- i=" + i);
131 wait();
132 System.out.println(Thread.currentThread().getName() + " 执行了wait操作" + " 执行了wait操作" + " -- i=" + i);
133 } catch (InterruptedException e) {
134 e.printStackTrace();
135 }
136 } else {
137 // 开始取钱
138 System.out.println(Thread.currentThread().getName() + " 取钱:" + drawAmount + " -- i=" + i);
139 setBalance(getBalance() - drawAmount);
140
141 flag = false;
142
143 // 唤醒其他线程
144 notifyAll();
145
146 System.out.println(Thread.currentThread().getName() + "-- 取钱 -- 执行完毕" + " -- i=" + i); // 3
147 }
148 }
149
150 }
上面的例子演示了wait()/notify()/notifyAll()的用法。部分输出结果为:
1 取钱线程 开始要执行wait操作 执行了wait操作 -- i=0
2 存钱线程 存款:700.0 -- i=0
3 存钱线程-- 存钱 -- 执行完毕 -- i=0
4 存钱线程 开始要执行wait操作 -- i=1
5 取钱线程 执行了wait操作 执行了wait操作 -- i=0
6 取钱线程 取钱:700.0 -- i=1
7 取钱线程-- 取钱 -- 执行完毕 -- i=1
8 取钱线程 开始要执行wait操作 执行了wait操作 -- i=2
9 存钱线程 执行了wait操作 -- i=1
10 存钱线程 存款:700.0 -- i=2
11 存钱线程-- 存钱 -- 执行完毕 -- i=2
12 取钱线程 执行了wait操作 执行了wait操作 -- i=2
13 取钱线程 取钱:700.0 -- i=3
14 取钱线程-- 取钱 -- 执行完毕 -- i=3
15 取钱线程 开始要执行wait操作 执行了wait操作 -- i=4
16 存钱线程 存款:700.0 -- i=3
17 存钱线程-- 存钱 -- 执行完毕 -- i=3
18 存钱线程 开始要执行wait操作 -- i=4
19 取钱线程 执行了wait操作 执行了wait操作 -- i=4
20 取钱线程 取钱:700.0 -- i=5
21 取钱线程-- 取钱 -- 执行完毕 -- i=5
22 取钱线程 开始要执行wait操作 执行了wait操作 -- i=6
23 存钱线程 执行了wait操作 -- i=4
24 存钱线程 存款:700.0 -- i=5
25 存钱线程-- 存钱 -- 执行完毕 -- i=5
26 存钱线程 开始要执行wait操作 -- i=6
27 取钱线程 执行了wait操作 执行了wait操作 -- i=6
28 取钱线程 取钱:700.0 -- i=7
29 取钱线程-- 取钱 -- 执行完毕 -- i=7
30 取钱线程 开始要执行wait操作 执行了wait操作 -- i=8
31 存钱线程 执行了wait操作 -- i=6
32 存钱线程 存款:700.0 -- i=7
由此,我们需要注意如下几点:
1.wait()方法执行后,当前线程立即进入到等待阻塞状态,其后面的代码不会执行;
2.notify()/notifyAll()方法执行后,将唤醒此同步锁对象上的(任意一个-notify()/所有-notifyAll())线程对象,但是,此时还并没有释放同步锁对象,也就是说,如果notify()/notifyAll()后面还有代码,还会继续进行,知道当前线程执行完毕才会释放同步锁对象;
3.notify()/notifyAll()执行后,如果右面有sleep()方法,则会使当前线程进入到阻塞状态,但是同步对象锁没有释放,依然自己保留,那么一定时候后还是会继续执行此线程,接下来同2;
4.wait()/notify()/nitifyAll()完成线程间的通信或协作都是基于不同对象锁的,因此,如果是不同的同步对象锁将失去意义,同时,同步对象锁最好是与共享资源对象保持一一对应关系;
5.当wait线程唤醒后并执行时,是接着上次执行到的wait()方法代码后面继续往下执行的。
当然,上面的例子相对来说比较简单,只是为了简单示例wait()/notify()/noitifyAll()方法的用法,但其本质上说,已经是一个简单的生产者-消费者模式了。
笔者水平有限,若有错漏,欢迎指正,如果转载以及CV操作,请务必注明出处,谢谢!