synchronized(obj) {
while(!condition) {
obj.wait();
}
obj.doSomething();
}
当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait() , 放弃对象锁.
之后在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:
synchronized(obj) {
condition = true;
obj.notify();
}
需要注意的概念是:
# 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {…} 代码段内。
# 调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {…} 代码段内唤醒A。
# 当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
# 如果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中的一个才有机会获得锁继续执行。
比如下述代码,在SubThread中,如果只是notify,而没有wait,那么SubThread仍然持有lock锁,MyThread虽然被唤醒,但是仍然要等待SubThread执行结束。
- package test.thread;
- //2个线程交替打印。线程1打印奇数,线程2打印偶数
- public class ThreadTest {
- /**
- * @param args
- */
- public static void main(String[] args) {
- String lock = "lock";
- MyThread myThread = new MyThread(lock);
- Thread t1 = new Thread(myThread);
- t1.start();
- try {
- // 确保线程t1先执行
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- SubThread sub = new SubThread(lock);
- Thread t2 = new Thread(sub);
- t2.start();
- }
- }
- class MyThread implements Runnable {
- String lock;
- public MyThread(String lock) {
- this.lock = lock;//当前线程获得lock对象的引用
- }
- public void run() {
- int i = 0;
- // 使用lock对象作为监视器
- synchronized (lock) {//在lock对象上加锁
- System.out.println("The first thread.获得锁");
- while (i++ < 20) {
- try {
- // 每次暂停500毫秒是为了更好地看到效果
- Thread.sleep(500);
- if (i%2==1) {
- System.out.println("The first thread.-->" + i);
- // 调用lock监视器的wait()方法,通知本线程释放监视器,本线程等待
- // 其他也使用lock对象作为监视器的线程唤醒的时候,本线程得以继续运行
- System.out.println("The first thread 被阻塞");
- lock.wait();
- // 下面的wait(long timeout)表示:若等待5秒后还没有别的线程来唤醒的话,则本线程继续执行
- // lock.wait(5000);
- }else{
- System.out.println("The first thread 解锁lock");
- lock.notify();
- }
- //这个线程当是奇数时,打印数字,打印后,此线程wait。当是偶数时,什么都不做,只是激活lock对象
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
- class SubThread implements Runnable {
- String lock;
- public SubThread(String lock) {
- this.lock = lock;
- }
- public void run() {
- int i = 1;
- // 这个线程也使用lock对象作为监视器
- synchronized (lock) {
- System.out.println("The second thread.获得锁");
- while (i < 20) {
- try {
- Thread.sleep(500);
- if (i%2==0) {
- System.out.println("The second thread.-->" + i);
- // 调用lock监视器的wait()方法,通知本线程释放监视器,本线程等待
- // 其他也使用lock对象作为监视器的线程唤醒的时候,本线程得以继续运行
- System.out.println("The second thread 解锁lock");
- lock.notify();
- System.out.println("The second thread 被阻塞");
- lock.wait();
- // 下面的wait(long timeout)表示:若等待5秒后还没有别的线程来唤醒的话,则本线程继续执行
- // lock.wait(5000);
- }else{
- System.out.println("The second thread 什么也没干");
- //lock.notify();
- }
- i++;
- //这个线程2,当线程1的wait调用时,此线程2激活。当i是偶数时,打印i,打印后,通知lock解锁(此时thread1得锁,干活),并且此线程2被阻塞
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- // 调用lock对象的notify()方法,唤醒同一对象监视器中调用wait的第一线程
- // 或者调用notifyAll()方法,唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行
- //lock.notify();
- }
- }
- }