web容器可能决定一个Servlet是否从servic中移除(例如,当一个容器想要回收内存资源时或者被关闭时)。在上面的场景中,容器会调用Servlet接口的destroy方法。在方法中,可以释放servlet使用的任何资源,保存持久化状态。destroy方法关闭在init方法中创建的数据库对象。
当servlet被移除时,它的service方法必须全部执行完成。服务器在所有请求被响应或者在一个特定时间后,通过调用destroy方法确保这一点的实现。当你的servlet正在执行超过服务器超时时间的长任务时,这些操作直到destroy方法被调用前都在执行。你必须确保任何持有客户端请求的线程完成。
本节的其余部分将介绍如何执行以下操作:
保持跟踪当前有多少线程在运行service方法
通过destroy方法通知长时间运行的线程关闭并等待完成来提供一个干净的关闭方法
让长时间运行的方法定期轮询以检查关闭,并在必要时停止工作,清理和返回
跟踪服务请求
要跟踪服务请求,需要在servlet类中包含一个变量,这个变量用来统计运行的service方法数量。这个变量需要使用同步方法增量、减量和返回变量值。
public class ShutdownExample extends HttpServlet {
private int serviceCounter = 0;
...
// Access methods for serviceCounter
protected synchronized void enteringServiceMethod() {
serviceCounter++;
}
protected synchronized void leavingServiceMethod() {
serviceCounter--;
}
protected synchronized int numServices() {
return serviceCounter;
}
}
当每次进入service方法时都需要增长变量值,每次离开service方法时都需要减小变量值。这是你要在HttpServlet子类覆写父类service方法的原因之一。新方法需要调用super.service()保留原始的service方法的内容。
protected void service(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException,IOException {
enteringServiceMethod();
try {
super.service(req, resp);
} finally {
leavingServiceMethod();
}
}
通知方法关闭
为了确保一个干净的关闭,在所有请求完成前你的service方法不能释放任何共享资源。做到这一点的一部分是检查service的数量。另外一部分是通知长时间运行的任务是时候关闭了。为了能通知到位,需要另一个变量。这个变量需要有通常的访问方法。
public class ShutdownExample extends HttpServlet {
private boolean shuttingDown;
...
//Access methods for shuttingDown
protected synchronized void setShuttingDown(boolean flag) {
shuttingDown = flag;
}
protected synchronized boolean isShuttingDown() {
return shuttingDown;
}
}
下面是一个使用这些变量提供干净的关闭方法的示例:
public void destroy() {
/* Check to see whether there are still service methods /*
/* running, and if there are, tell them to stop. */
if (numServices()> 0) {
setShuttingDown(true);
}
/* Wait for the service methods to stop. */
while (numServices()> 0) {
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
}
}
}
创建规范的长期运行方法
提供干净关闭的最后一步是使任何长时间运行的方法都比较规范。可能需要长期运行的方法需要检查通知他们关闭的变量并在需要时强制打断正在执行的工作。
public void doPost(...) {
...
for(i = 0; ((i < lotsOfStuffToDo) &&
!isShuttingDown()); i++) {
try {
partOfLongRunningOperation(i);
} catch (InterruptedException e) {
...
}
}
}