我正在为机器人竞赛制作一个基于网络的评分系统。当得分时,我想刷新每个观看比赛的人的页面。我的代码正在“正确”工作。
我的问题是,当我测试并打开大约5到10个网页时,我要求的任何其他页面在我关闭某些页面之前都不会被处理。我认为发生的事情是request.startAsync()没有释放线程而且它正在无限期地等待。
我已经在Jetty 9.2.7.v20150116和Tomcat7上进行了测试。两者都有相同的缓慢行为。
// Display a game with all it's events
// http://stackoverflow.com/questions/10878243/sse-and-servlet-3-0
@WebServlet(urlPatterns = { "/gameRefresh" }, asyncSupported = true)
public class GameRefreshController extends HttpServlet
{
private static final long serialVersionUID = -6890088129187673292L;
private static AtomicBoolean refreshNeeded = new AtomicBoolean();
private final Queue<AsyncContext> ongoingRequests = new ConcurrentLinkedQueue<>();
private ScheduledExecutorService service;
public static void setRefreshNeeded(boolean value)
{
refreshNeeded.set(value);
}
@Override
public void init(ServletConfig config) throws ServletException
{
final Runnable notifier = new Runnable()
{
@Override
public void run()
{
// Don't refresh if it's not needed.
if(!refreshNeeded.get())
{
return;
}
// This var is set by the backend when an event occurs.
setRefreshNeeded(false);
final Iterator<AsyncContext> iterator = ongoingRequests.iterator();
// not using for : in to allow removing items while iterating
while (iterator.hasNext())
{
AsyncContext asyncContext = iterator.next();
final ServletResponse servletResponse = asyncContext.getResponse();
PrintWriter out;
try
{
out = servletResponse.getWriter();
String toOutput = "data: refresh\n\n";
out.write(toOutput);
out.checkError();
}
catch(IOException exception)
{
// iterator is always removed because we refresh the whole page.
}
finally
{
iterator.remove();
}
}
}
};
service = Executors.newScheduledThreadPool(1);
service.scheduleAtFixedRate(notifier, 1, 1, TimeUnit.SECONDS);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/event-stream");
response.setCharacterEncoding("UTF-8");
request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
final AsyncContext asyncContext = request.startAsync();
asyncContext.setTimeout(0);
asyncContext.addListener(new AsyncListener()
{
@Override
public void onComplete(AsyncEvent event) throws IOException
{
ongoingRequests.remove(asyncContext);
}
@Override
public void onTimeout(AsyncEvent event) throws IOException
{
ongoingRequests.remove(asyncContext);
}
@Override
public void onError(AsyncEvent event) throws IOException
{
ongoingRequests.remove(asyncContext);
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException
{
}
});
ongoingRequests.add(asyncContext);
}
}