------- android培训、java培训、期待与您交流! ----------
Object的Wait方法
导致当前线程等待直到另一个线程在这个对象上调用notify()方法或者notifyAll()方法。换句话说,这个方法的表现就像它简单的处理调用wait(0)方法。
当前线程必须拥有这个对象监视器。调用之后当前线程释放这个监视器的拥有权并等待直到另一个线程唤醒等待在这个对象的监视器上的多个线程,为了唤醒或者调用notify方法或者调用notifyAll方法。然后线程等待直到它重新获取监视器(或者锁)的拥有权并恢复执行。
在一个参数版本的情况下,中断和伪唤醒可能发生,所以这个方法应该总是被用在一个循环中。
synchronized (obj) {
while ()
obj.wait();
... // Perform action appropriate to condition
}
这个方法只应该被一个拥有这个对象的监视器的线程调用。查看 notify 方法的描述关于一个线程成为监视器拥有者的方法。
Throws:
IllegalMonitorStateException
- 如果当前线程不是对象监视器拥有者
InterruptedException
- 如果任何线程在之前中断了当前线程或者在当前线程等待唤醒时被中断。中断状态在这个异常被抛出后被清除。
Object的notify方法
方法签名:public final void notify()
final表明这个方法是不能被子类覆盖的,所以任何对象调用的notify方法都是继承自Object的方法,也就是notify方法一定是Object实现的。
唤醒一个等待在这个对象的监视器上的线程。如果若干线程等待在这个对象上他们中的一个会被选择唤醒。这个选择是随机的,由具体实现决定,通过调用对象的任意一个wait方法一个线程就会等待在这个对象的监视器上。
唤醒的线程将不能执行直到当前线程放弃这个对象上的锁。唤醒的线程会用通常的方式和任何其他可能被激活的同样等待在这个对象上的竞争者竞争;例如唤醒的线程在成为下一个锁上这个对象的线程时不会有任何可靠地特权或者不利条件。
这个方法只能被拥有这个对象的监视器的线程调用。一个线程可以通过如下三种方法获取到对象的监视器:
1.通过执行一个对象的同步的实例方法
2.通过执行一个同步在这个对象上的同步代码块
3.对于类类型对象,通过执行那个类的同步静态方法。
同一时刻只有一个线程可以拥有一个对象的监视器。
Throws:
IllegalMonitorStateException
- 如果当前线程不是这个对象的监视器的拥有者。
线程通信的例子,这个例子会用两种方式实现。
目标:子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着在回到主线程循环100次,如此循环50次
第一种:实现方式没有采用封装的设计思想
package com.test;
public class TraditionalThreadCommunication
{
private static boolean exchange=true;
public static void main(String[] args)
{
new Thread(new Runnable()
{
@Override
public void run()
{
for (int j = 1; j <= 50; j++)
{
synchronized (TraditionalThreadCommunication.class)
{
while(!exchange)
{
try
{
TraditionalThreadCommunication.class.wait();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
for (int i = 1; i <= 10; i++)
{
System.out.println("sub Thread--->" + i
+ " | loop of --->" + j);
}
exchange=false;
TraditionalThreadCommunication.class.notify();
}
}
}
}).start();
for (int j = 1; j <= 50; j++)
{
synchronized (TraditionalThreadCommunication.class)
{
while(exchange)
{
try
{
TraditionalThreadCommunication.class.wait();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
for (int i = 1; i <= 100; i++)
{
System.out.println("main Thread--->" + i
+ " | loop of --->" + j);
}
exchange=true;
TraditionalThreadCommunication.class.notify();
}
}
}
}
第二种:使用高内聚低耦合的设计思想,将两个打印方法封装到同一个类中,这样加锁较为方便,并且这个封装的类在之后其他的调用都是可以通信的。
package com.test;
public class TraditionalThreadCommunication2
{
public static void main(String[] args)
{
Business business = new Business();
new Thread(new Runnable(){
@Override
public void run()
{
for(int i=1;i<=500;i++)
{
business.sub(i);
}
}
}).start();
for(int i=1;i<=500;i++)
{
business.main(i);
}
}
}
class Business
{
private boolean bShouldSub=true;
synchronized void sub(int i)
{
while(!bShouldSub)
{
try
{
this.wait();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
for(int j=1;j<=10;j++)
{
System.out.println("sub Thread--->"+j+" | loop of--->"+i);
}
bShouldSub=false;
this.notify();
}
synchronized void main(int i)
{
while(bShouldSub)
{
try
{
this.wait();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
for(int j=1;j<=100;j++)
{
System.out.println("main Thread--->"+j+" | loop of--->"+i);
}
bShouldSub=true;
this.notify();
}
}