需要开启一个线程,这个线程一直阻塞等待某件事情发生,最后主线程退出时将这个线程终止。
线程是这样的:
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()并不代表线程池就一定立即就能退出,它可能必须要等待所有正在执行的任务都执行完成了才能退出。