需要开启一个线程,这个线程一直阻塞等待某件事情发生,最后主线程退出时将这个线程终止。
线程是这样的:
public class WatcherThread implements Runnable{
private boolean dead = false;
@Override
public void run() {
try {
synchronized (this) {
while (!dead) {
wait();
}
System.out.println("线程退出");
}
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
//...其他代码
/**
* 关闭当前监视者线程
*/
public void close()
{
this.dead = true;
synchronized (this) {
//注意,notify必须放在同步代码块中,与wait配合使用
notify();
}
}
}
watcher = new WatcherThread();
//开启线程,等待接收Zookeeper数据变化
executor = Executors.newCachedThreadPool();
executor.execute(watcher);
主线程终止这个线程:
watcher.close();
if(executor != null)
{
executor.shutdown();
}
有几点需要注意:
(1)wait与notify/notifyAll
wait会一直阻塞在某一个对象之上,之后某个线程在该对象上调用notify/notifyAll方法,才会使得wait的线程回到就绪状态,但是不一定立即执行。
wait,notify,notifyAll这些方法是Object类的一部分,而不是Thread的一部分,所以可以把他们放进任何同步控制方法中。
实际上,只能在同步控制方法/同步控制块中调用wait,notify,notifyAll这几个方法,如果在非同步控制方法里面调用了这几个方法,可以编译通过,但是运行的时候会获得IllegalMonitorStateException异常。
注意:一般来说,wait和notify放在synchronozed(object)同步块中,并由这个object来调用。如果是synchronized(this),那么就直接调用。
(2)shutdown与shutdownNow
当线程池调用shutdown时,线程池的状态则立刻变成SHUTDOWN状态。此时,则不能再往线程池中添加任何任务,否则将会抛出RejectedExecutionException异常。但是,此时线程池不会立刻退出,直到添加到线程池中的任务都已经处理完成,才会退出。
执行 shutdownNow() 方法,线程池的状态立刻变成STOP状态,并试图停止所有正在执行的线程,不再处理还在池队列中等待的任务,当然,它会返回那些未执行的任务。
它试图终止线程的方法是通过调用Thread.interrupt()方法来实现的,但是大家知道,这种方法的作用有限,如果线程中没有sleep 、wait、Condition、定时锁等应用, interrupt()方法是无法中断当前的线程的。所以,ShutdownNow()并不代表线程池就一定立即就能退出,它可能必须要等待所有正在执行的任务都执行完成了才能退出。