Java之Object.WAIT()
2015-09-03 10:50
579 查看
Java中,Object自身实现了如下方法:
Java中,每个对象都有wait和notify成员函数,他们是Java的native方法。本文将对这两个方法的使用进行描述。
先看例子:
输出结果为:
这里顺便说一下,join的作用是等待该线程执行结束。如果上面代码中,t1.join();在t2.start();之前执行,那么这个程序就死锁了。下面回归正题。
local对象是两个线程共享的对象,在t1中,local调用wait方法;t1挂起,等待local的notify方法被调用。t2中,local调用notify方法,唤醒t1线程。这样就实现了线程的前驱关系。
需要注意的概念是:
# 调用wait(), notify()方法前,必须获得这个对象的锁,也就是必须写在synchronized(obj) {} 代码段内;否则会报错(见附录代码1)。
# 调用wait()后,持有该对象锁的线程会放弃锁。于是t1线程就释放了local的锁,t2才获得local的锁。
# 调用notify()后,持有该对象锁的线程在退出共享代码块后会放弃锁。于是t2线程就释放了local的锁,t1才获得local的锁。
# 如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
# obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
# 当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。
前面讲了wait/notify机制,Thread还有一个sleep()静态方法,它也能使线程暂停一段时间。sleep与wait的不同点是: sleep并不释放锁,但会放弃cpu,使其他线程可以使用cpu,时间到后,会自动恢复执行。obj.wait会使线程进入obj对象的等待集合中并等待唤醒。
但是wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException。
如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法。如果此刻线程B正在 wait/sleep/join,则线程B会立刻抛出InterruptedException,在catch() {} 中直接return即可安全地结束线程。
需要注意的是,InterruptedException是线程自己从内部抛出的,并不是interrupt()方法抛出的。对某一线程调用 interrupt()时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。但是,一旦该线程进入到 wait()/sleep()/join()后,就会立刻抛出InterruptedException。
关于这一问题,请看下面例子:
结果:
在t2的run方法中,t1调用interrupt方法,那么t1会立刻被打断,进入其catch的代码块。t2则继续执行。
附录代码1:
Java中,每个对象都有wait和notify成员函数,他们是Java的native方法。本文将对这两个方法的使用进行描述。
先看例子:
public class LmxWaitSleep { static String local = "local"; static Thread t1 = new Thread() { @Override public void run() { System.out.println("t1 in"); try { synchronized (local) { local.wait(); System.out.println("t1 continue"); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("t1 out"); } }; static Thread t2 = new Thread() { @Override public void run() { try { Thread.sleep(100); System.out.println("t2 in"); System.out.println("t2 sleep"); // t1.interrupt(); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (local) { local.notify(); System.out.println("another sleep"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("waked up"); } System.out.println("t2 out"); } }; public static void main(String[] args) throws InterruptedException { t1.start(); t2.start(); t1.join(); t2.join(); } }
输出结果为:
t1 in t2 in t2 sleep another sleep waked up t2 out t1 continue t1 out
这里顺便说一下,join的作用是等待该线程执行结束。如果上面代码中,t1.join();在t2.start();之前执行,那么这个程序就死锁了。下面回归正题。
local对象是两个线程共享的对象,在t1中,local调用wait方法;t1挂起,等待local的notify方法被调用。t2中,local调用notify方法,唤醒t1线程。这样就实现了线程的前驱关系。
需要注意的概念是:
# 调用wait(), notify()方法前,必须获得这个对象的锁,也就是必须写在synchronized(obj) {} 代码段内;否则会报错(见附录代码1)。
# 调用wait()后,持有该对象锁的线程会放弃锁。于是t1线程就释放了local的锁,t2才获得local的锁。
# 调用notify()后,持有该对象锁的线程在退出共享代码块后会放弃锁。于是t2线程就释放了local的锁,t1才获得local的锁。
# 如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
# obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
# 当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。
前面讲了wait/notify机制,Thread还有一个sleep()静态方法,它也能使线程暂停一段时间。sleep与wait的不同点是: sleep并不释放锁,但会放弃cpu,使其他线程可以使用cpu,时间到后,会自动恢复执行。obj.wait会使线程进入obj对象的等待集合中并等待唤醒。
但是wait()和sleep()都可以通过interrupt()方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException。
如果线程A希望立即结束线程B,则可以对线程B对应的Thread实例调用interrupt方法。如果此刻线程B正在 wait/sleep/join,则线程B会立刻抛出InterruptedException,在catch() {} 中直接return即可安全地结束线程。
需要注意的是,InterruptedException是线程自己从内部抛出的,并不是interrupt()方法抛出的。对某一线程调用 interrupt()时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。但是,一旦该线程进入到 wait()/sleep()/join()后,就会立刻抛出InterruptedException。
关于这一问题,请看下面例子:
package test.thread.wait; public class LmxWaitSleep { static String local = "local"; static boolean letT1 = false; static Thread t1 = new Thread() { @Override public void run() { System.out.println("t1 in"); try { synchronized (local) { while(!letT1) { local.wait(); } System.out.println("t1 continue"); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("t1 out"); } }; static Thread t2 = new Thread() { @Override public void run() { try { Thread.sleep(100); System.out.println("t2 in"); System.out.println("t2 sleep"); t1.interrupt(); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (local) { letT1 = true; local.notify(); System.out.println("another sleep"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("waked up"); } System.out.println("t2 out"); } }; public static void main(String[] args) throws InterruptedException { t1.start(); t2.start(); t1.join(); t2.join(); } }
结果:
t1 in t2 in t2 sleep java.lang.InterruptedException t1 out at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:503) at test.thread.wait.#Cabinathor$1.run(Cabinathor.java:13) another sleep waked up t2 out
在t2的run方法中,t1调用interrupt方法,那么t1会立刻被打断,进入其catch的代码块。t2则继续执行。
附录代码1:
public class LmxWaitSleep { static String local = "local"; static boolean letT1 = false; static Thread t1 = new Thread() { @Override public void run() { System.out.println("t1 in"); try { // synchronized (local) { if(!letT1) { local.wait(); } System.out.println("t1 continue"); // } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("t1 out"); } }; static Thread t2 = new Thread() { @Override public void run() { try { Thread.sleep(100); System.out.println("t2 in"); System.out.println("t2 sleep"); // t1.interrupt(); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (local) { letT1 = true; local.notify(); yield(); System.out.println("another sleep"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("waked up"); } System.out.println("t2 out"); } }; public static void main(String[] args) throws InterruptedException { t1.start(); t2.start(); t1.join(); t2.join(); } }
t1 in Exception in thread "Thread-0" java.lang.IllegalMonitorStateException at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:503) at basic.thread.wait.LmxWaitSleep$1.run(LmxWaitSleep.java:13) t2 in t2 sleep another sleep waked up t2 out因为没有获得local的锁‘(监视器),所以wait的时候,没锁的时候,就会出问题。
相关文章推荐
- Oreilly Cocoa and Objective C Up and Running
- Objective-C使用位运算设计可复选的枚举
- 【《Objective-C 高级编程》 学习笔记--GCD】
- objective-c 下面int 和 NSData数据 互相转换的方法
- Objective-C之类的声明与创建
- Objective-C类初始化:load与initialize
- Object对象详解(四)之wait与notify/notifyAll
- Object-C中的Category
- 视频播放插件 swfobject
- js报错“TypeError: 'stepUp' called on an object that does not implement interface HTMLInputElement”
- CRITICAL_OBJECT_TERMINATION (f4)
- Objective-C 学习笔记 9 多态,动态类型,动态绑定
- JSONObject介绍与操作
- 编写高质量的Objective-C代码
- objective c代码规范
- Objectvie-C之 NSString 处理技巧-分割字符串
- enumerateKeysAndObjectsUsingBlock 的用法
- 把NSObject对象输出为字典
- JSON通过配置文件格式化时间属性(解决[object Object]问题)
- Html emed 和 object