核心架構
- TaskBean:實作
Runnable、Serializable,封裝長時間任務(模擬 1~100 累加,每步 100ms,共 10 秒)。
- start.jsp:建立 TaskBean 存入 Session,啟動新執行緒執行
run(),轉發至 status.jsp。
- status.jsp:輪詢
TaskBean.getPercent() 顯示進度條,任務完成則顯示結果。
- stop.jsp:呼叫
setRunning(false) 中斷任務。
TaskBean 關鍵代碼
public class TaskBean implements Runnable, Serializable {
private int counter = 0, sum = 0;
private boolean started = false, running = false;
private int sleep = 100;
public synchronized void setRunning(boolean running) {
this.running = running;
if (running) started = true;
}
public synchronized int getPercent() { return counter; }
public synchronized boolean isCompleted() { return counter == 100; }
public synchronized Object getResult() {
return isCompleted() ? new Integer(sum) : null;
}
protected void work() {
try { Thread.sleep(sleep); counter++; sum += counter; }
catch (InterruptedException e) { setRunning(false); }
}
public void run() {
try { setRunning(true); while (isRunning() && !isCompleted()) work(); }
finally { setRunning(false); }
}
// getter/setter 略
}
JSP 頁面流程
start.jsp
<% session.removeAttribute("task"); %>
<jsp:useBean id="task" scope="session" class="test.barBean.TaskBean"/>
<% task.setRunning(true); new Thread(task).start(); %>
<jsp:forward page="status.jsp"/>
status.jsp(自動刷新)
<jsp:useBean id="task" scope="session" class="test.barBean.TaskBean"/>
<html><head>
<meta http-equiv="refresh" content="1"> <!-- 每秒刷新 -->
<title>任務進度</title>
</head><body>
<% if (!task.isStarted()) { %>
任務尚未啟動...
<% } else if (task.isRunning()) { %>
進度: <%= task.getPercent() %>% <br>
<div style="width:300px;border:1px solid #000">
<div style="width:<%=task.getPercent()%>%;background:#090;height:20px"></div>
</div>
<% } else if (task.isCompleted()) { %>
完成! 結果 = <%= task.getResult() %>
<% } %>
</body></html>
關鍵設計重點
- Session 共享 Bean:
scope="session" 確保同一用戶多請求存取同一任務實例。
- 執行緒安全:所有狀態方法加
synchronized,避免 JSP 執行緒與任務執行緒競態。
- 立即回應:
start.jsp 瞬間返回,使用者無感等待,體驗大幅提升。
- 輪詢頻率:
meta refresh="1" 或 AJAX 定時請求,視任務長短調整。
實務延伸
- 真實場景:複雜報表產生、大量資料匯入、影片轉碼、郵件群發。
- 生產環境建議:使用
ExecutorService 管理執行緒池、引入 Future 追蹤、採用 WebSocket/Server-Sent Events 取代輪詢、任務狀態持久化至資料庫支援叢集。