前言
当一个线程等待另一个线程执行完某个任务后,才继续往下执行,这个时候就需要实现线程间通信。
Java中实现线程间通信使用的是wait(),notify().notifyAll()方法来实现。
这些方法都是Object类的方法。
从下面可以看出,可以实现无限等待和定时长等待,假如在等待期间,发生中断,将会抛出异常。
public final void wait() throws InterruptedException {
wait(0);
}
public final void wait(long timeout, int nanos)throws InterruptedException;
public final native void wait(long timeout)throws InterruptedException ;
public final native void notify();
public final native void notifyAll();
需要注意的是,这些方法必须在同步块中使用,否则将会抛出
IllegalMonitorStateException异常,IllegalMonitorStateException是RuntimeException的子类。
notify():随机选取一个进行通知
notifyAll():通知所有
使用wait时,线程会释放当前所持有的锁。
实现
范例程序
package org.wait;
public class WaitThread {
public static void main(String[] args) {
// TODO Auto-generated method stub
Object lock = new Object();
Thread1 th1 = new Thread1(lock);
Thread2 th2 = new Thread2(lock);
System.out.println(th1.getName() + " 执行");
th1.start();
System.out.println("等待1000ms");
try {
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
}
System.out.println(th2.getName() + " 执行");
th2.start();
}
}
/**
* 等待通知
* @author lgj
*
*/
class Thread1 extends Thread{
Object lock;
public Thread1(Object lock) {
super();
this.lock = lock;
}
@Override
public void run() {
System.out.println(this.getName() + " 执行wait(),等待通知......," + "当前时间:" + System.currentTimeMillis());
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(this.getName() + " 获得通知," + "当前时间:" + System.currentTimeMillis());
}
}
/**
* 发送通知
* @author lgj
*
*/
class Thread2 extends Thread{
Object lock;
public Thread2(Object lock) {
super();
this.lock = lock;
}
@Override
public void run() {
System.out.println(this.getName() + " 发送通知," + "当前时间:" + System.currentTimeMillis());
synchronized (lock) {
lock.notify();
}
}
}
输出
Thread-0 执行
等待1000ms
Thread-0 执行wait(),等待通知......,当前时间:1529858245307
Thread-1 执行
Thread-1 发送通知,当前时间:1529858246308
Thread-0 获得通知,当前时间:1529858246308
notify()和notifyAll()区别
notify():随机选取一个进行通知
notifyAll():通知所有
使用Join等待另一个线程执行结束
在一些情况下,父线程创建子线程并启动子线程,如果子线程的任务比较多,那么父线程往往会先执行完,如果父线程想等待子线程执行完获取某些结果,才继续往下执行,这时可以使用Thread类的Join(),方法实现。
join()可以无限期等待或者设置超时时间。
并且等待期间出现Interrupted中断时将会抛出异常。
public final void join() throws InterruptedException;
public final synchronized void join(long millis, int nanos)
throws InterruptedException
public final synchronized void join(long millis)
throws InterruptedException
范例程序
package org.wait;
public class JoinThread {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("主线程开始执行,当前时间 = " + System.currentTimeMillis()%10000);
Thread3 th3 = new Thread3();
th3.start();
System.out.println("主线程等待线程" + th3.getName() + " 执行,当前时间 = " + System.currentTimeMillis()%10000);
try {
th3.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主线程继续执行,当前时间 = " + System.currentTimeMillis()%10000);
}
}
class Thread3 extends Thread{
@Override
public void run() {
System.out.println(this.getName()+" 线程开始执行,当前时间 = " + System.currentTimeMillis()%10000);
try {
Thread.sleep(2000);
} catch (Exception e) {
// TODO: handle exception
}
System.out.println(this.getName()+" 线程结束执行,当前时间 = " + System.currentTimeMillis()%10000);
}
}
输出
主线程开始执行,当前时间 = 7764
主线程等待线程Thread-0 执行,当前时间 = 7765
Thread-0 线程开始执行,当前时间 = 7765
Thread-0 线程结束执行,当前时间 = 9766
主线程继续执行,当前时间 = 9767
join(long)和sleep(long)的区别
这两个方法都是Thread 类的方法。
join(long)
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
join(long)内部使用的是wait(long)实现,所以具有释放锁的特点。而sleep(long)却不会释放锁。