转:jsp调用长时间运行java 程序,如何防止浏览器超时断连

转:中文:http://blog.csdn.net/pengchua/archive/2008/03/27/2223823.aspx

转:英文:http://onjava.com/pub/a/onjava/2003/06/11/jsp_progressbars.html

中英文的方法一样,英文的讲解的更详细一些

=======================中文版=============================

采用线程不断向页面传达递信息:实现如下:

import java.io.Serializable;

public class TaskBean implements Runnable, Serializable ...{
private boolean started;
private boolean running;
private int sleep;
private Task  task;
public TaskBean() ...{
        started = false;
        running = false;
        sleep = 100;
        task=new Task();
    }

protected void work() ...{
try ...{
            Thread.sleep(sleep);
            task.work();
        } catch (InterruptedException e) ...{
            setRunning(false);
        }
    }

// 如果任务已经启动,isStarted()方法将返回true:
public synchronized boolean isStarted() ...{
return started;
    }

// 如果任务已经完成,isCompleted()方法将返回true:
public synchronized boolean isCompleted() ...{
return task.isIfCompleted();
    }

// 如果任务正在运行,isRunning()方法将返回true:
public synchronized boolean isRunning() ...{
return running;
    }

public synchronized void setRunning(boolean running) ...{
this.running = running;
if (running)
            started = true;
    }

public void run() ...{
try ...{
            setRunning(true);
while (isRunning() && !isCompleted())
                work();
        } finally ...{
            setRunning(false);
        }
    }
}

package com;

public class Task ...{

private boolean ifCompleted=false;


public Task() ...{
super();
// TODO Auto-generated constructor stub
    }



public boolean isIfCompleted() ...{
return ifCompleted;
    }



public void setIfCompleted(boolean ifCompleted) ...{
this.ifCompleted = ifCompleted;
    }



public void work()...{
for(int i=0;i<1000;i++)...{
for(int j=0;j<1000;j++)
for(int k=0;k<1000;k++)
for(int m=0;m<1000;m++)
for(int n=0;n<1000;n++)
for(int p=0;p<1000;p++)
            System.out.println("aaa-->"+j);
        }
this.setIfCompleted(true);
    }

/** *//**
     * @param args
*/
public static void main(String[] args) ...{
// TODO Auto-generated method stub

    }

}

在程序中启动:
TaskBean task=new TaskBean();
task.setRunning(true);
new Thread(task).start();
request.getSession.setAttribute("task");
或在页面中:
<%
   session.removeAttribute("task");
   %>
 
    class="com.TaskBean"/>
  <% task.setRunning(true); %>
<% new Thread(task).start(); %>

status.jsp:
<%@ page language="java" import="java.util.*,com.TaskBean" pageEncoding="GBK"%>

    class="com.TaskBean"/>
//备注: 用于定位或示例一个javabeans组件。 首先会试图定位一个bean实例,如果这个bean不存在,那么 就会从一个class或模版中进行示例。
//

 
    JSP进度条
    <% if (task.isRunning()) { %>
        <script LANGUAGE="JavaScript">
            setTimeout("location='status.jsp'", 1000);
        </script>
    <% } %>

 
 








       
           

                <% if (task.isRunning()) { %>
                    程序正在执行,请等待!
                <% } else { %>
                    <% if (task.isCompleted()) { %>
                        数据生成完成!
                    <% }  }%>
           
         
           

           
           

======================英文版===================================

http://onjava.com/pub/a/onjava/2003/06/11/jsp_progressbars.html

Many web and enterprise applications must perform CPU-intensive operations, such as complex database queries or heavy XML processing. These tasks are handled by database systems or middleware components, but the results are presented to the user with the help of JSP. This article shows how to implement the front tier in order to improve the user experience and reduce the server load.

When a JSP invokes an expensive operation whose result cannot be cached (on the server side), the user will have to wait each time he requests the page. Eventually, the user will lose his patience and he'll click the browser's Refresh or Reload button. This leads to ignored page requests that do heavy processing.

This article's example solves the problem described above by starting the heavy task in a separate thread. The JSP page returns an immediate response indicating that the task was started and is running. From time to time, the page is reloaded automatically in order to report the progress of the heavy task that continues to run in its own thread until it is completed. The user may stop the task only if the application allows such an action. In the end, the JSP page reports the result.

Simulating a Heavy Task

This section presents the TaskBean class, which implements java.lang.Runnable so that its run() method can be executed in a thread that is started from a JSP page (named start.jsp). Another JSP page (named stop.jsp) will let the user stop the run() method's execution. The TaskBean class also implements the java.io.Serializable interface so that it can be used as a JavaBean in the JSP pages:

package com.devsphere.articles.progressbar;

import java.io.Serializable;

public class TaskBean implements Runnable, Serializable {
    private int counter;
    private int sum;
    private boolean started;
    private boolean running;
    private int sleep;

    public TaskBean() {
        counter = 0;
        sum     = 0;
        started = false;
        running = false;
        sleep   = 100;
    }
}

The "heavy task" implemented by TaskBean computes 1 + 2 + ... + 100. Instead of using the well-known formula for computing this sum -- 100 * (100 + 1) / 2 = 5050 -- the run() method calls work() 100 times. See its code below. The Thread.sleep() call makes sure that the task will take about 10 seconds.

protected void work() {
    try {
        Thread.sleep(sleep);
        counter++;
        sum += counter;
    } catch (InterruptedException e) {
        setRunning(false);
    }
}

The status.jsp page calls the following methods to find out the task status. The getPercent() method tells how much of the task was executed:

public synchronized int getPercent() {
    return counter;
}

The isStarted() method returns true if the task was started:

public synchronized boolean isStarted() {
    return started;
}

The isCompleted() method returns true if the task was completed:

public synchronized boolean isCompleted() {
    return counter == 100;
}

The isRunning() method returns true if the task is still running:

public synchronized boolean isRunning() {
    return running;
}

The setRunning() method is called by start.jsp and stop.jsp. When the running parameter is true, the task is also marked as started. Calling setRunning(false) will tell the run() method to stop its execution.

public synchronized void setRunning(boolean running) {
    this.running = running;
    if (running)
        started  = true;
}

The getResult() method returns the computed sum if the task was completed. Otherwise, it returns null:

public synchronized Object getResult() {
    if (isCompleted())
        return new Integer(sum);
    else
        return null;
}

The run() method calls work() as long as the running flag is true and completed is false. A real application's run() method would execute a complex SQL query, parse a large XML document, or invoke a CPU-intensive EJB method. Note that the heavy task might be executed on a remote server. The JSP page reporting the result has two choices: to wait for the task completion or to use a progress bar.

public void run() {
    try {
        setRunning(true);
        while (isRunning() && !isCompleted())
            work();
    } finally {
        setRunning(false);
    }
}
Starting the Task

To run the example, download the article's source code archive, unzip it, deploy the progressbar.war web application and open http://localhost:8080/progressbar/ in your browser. This will invoke start.jsp, which is the application's welcome page declared in the web.xml descriptor:


  
  




  
  
    
   
   
        
    
    
     
     start.jsp
    
    
    
   
   

  
  

The start.jsp page starts a thread to run the "heavy task," and then it forwards the HTTP request to status.jsp, whose response looks like Figure 1:

Running Task
Figure 1. A running task

The start.jsp page creates a TaskBean instance using the tag. The session scope allows other pages to retrieve the same bean object when the HTTP requests are coming from the same browser.

The page calls session.removeAttribute("task") to make sure that creates a new bean object rather than retrieving an old object, which might have been created by an earlier JSP request during the same user session.

Here is the code of the start.jsp page:

<% session.removeAttribute("task"); %>


  
  

<% task.setRunning(true); %>

<% new Thread(task).start(); %>


  
  

After creating the TaskBean object, start.jsp creates a Thread, passing the bean object as a Runnable instance. The start() method causes the newly created thread to execute the run() method of the TaskBean object.

There are now two threads running concurrently: the thread that executes the JSP page (the "JSP thread") and the thread created by the JSP page (the "task thread"). The start.jsp page uses to invoke status.jsp, which shows the progress bar and the task status. Both JSP pages are executed in the same JSP thread.

Setting the running flag to true in start.jsp makes sure that the "running" status is reported to the user even if the task thread's run() method doesn't get started by the time when the status.jsp page is executed in the JSP thread.

The two lines of Java code that set the running flag to true and start the task thread could be moved into the TaskBean class to form a new method that would be called from the JSP page. It usually is a good idea to move as much code as possible into the Java classes. In the case of this example, placing new Thread(task).start() into start.jsp makes very clear that the JSP thread creates and starts the task thread.

You must be careful when dealing with threads in JSP pages. Keep in mind that your threads and the JSP threads are executed concurrently. This is similar to desktop programming, when you have a thread processing GUI events and other threads executing application-specific tasks. However, in the JSP environment, the same page may be executed in multiple threads on behalf of multiple users. There are also situations when the same user makes multiple requests to the same page and those HTTP requests may be served concurrently, even though they are coming from the same user.

The status.jsp page uses an HTML-based progress bar to inform the user about the status of the task. The tag gets the bean object created by start.jsp:


  
  

The status.jsp page is refreshed automatically from time to time in order to reflect the status changes. The setTimeout("location='status.jsp'", 1000) JavaScript code changes the browser's location after 1000 milliseconds. The browser will request the status.jsp page without any user intervention.




    JSP Progress Bar
    <% if (task.isRunning()) { %>
        <script LANGUAGE="JavaScript">
            setTimeout("location='status.jsp'", 1000);
        </script>
    <% } %>


The progress bar is built as an HTML table with 10 cells. Each cell represents 10% of the time that is necessary to execute the task.

JSP Progress Bar

Result: <%= task.getResult() %>
<% int percent = task.getPercent(); %> <%= percent %>%

<% for (int i = 10; i <= percent; i += 10) { %>
 
<% } %> <% for (int i = 100; i > percent; i -= 10) { %>
 
<% } %>

The task may be in one of the following states: "Running," "Completed," "Not Started," and "Stopped."

At the end of the page, there is a button that lets the user stop or restart the task:

    
<% if (task.isRunning()) { %> Running <% } else { %> <% if (task.isCompleted()) { %> Completed <% } else if (!task.isStarted()) { %> Not Started <% } else { %> Stopped <% } %> <% } %>

<% if (task.isRunning()) { %>
<% } else { %>
<% } %>

If you don't stop the task, you'll see the 5050 result in about 10 seconds:

Completed Task
Figure 2. The completed task

Stopping the Task

The stop.jsp page stops the execution of the task by setting the running flag to false:


   
   

<% task.setRunning(false); %>


   
   

Note that it is not okay to call the Thread.stop() method, which was provided by the first Java version but was deprecated by JDK 1.2. The task should get the chance to stop itself by returning from the run() method when it is appropriate. Otherwise, the TaskBean object might remain in an invalid state.

Stopped Task
Figure 3. A stopped task

When you execute the application the first time, you'll notice some delay when the task is started. Also, when you click the "Stop" button for the first time, the task won't be stopped immediately. The JSP page compilation causes these delays. Once the JSP pages are compiled, the application will respond very quickly to the user requests (assuming that the server isn't overloaded and the network is working properly).

Progress Bars in Real Applications

A progress bar makes the user interface friendlier and may have a good effect on the server performance, because users won't cancel and restart an operation that tells them to be patient and shows them the progress. However, the threads created to execute the tasks consume system resources. You should consider using a thread pool that allows you to reuse the Thread objects. Refreshing the status page from time to time also increases the network traffic. Keep that page small and simple.

In many real-world cases, the heavy task cannot be stopped or its progress cannot be tracked. For example, when accessing or updating a relational database, you cannot stop an SQL statement in the middle of its execution. However, if the user has signaled that she wants to stop or to cancel the task, you could roll back the database transaction after the SQL statement is executed.

When you parse an XML document, there's no way to show the exact percentage of the parsed content. If you use DOM, you get the whole document tree after the parsing is completed. If you use SAX, you know what was parsed, but you usually don't know much about the remaining content that has to be parsed. In such a case, you can only try to estimate the progress of the heavy task.

Estimating the time necessary to execute a heavy task can be difficult, because it depends on the available CPU resources. You can't just do a few tests in the production environment because the server load changes in time. A simple solution is to measure the execution time of the heavy task every time it is invoked, and then use the average time of the last few executions as an estimate. For more accurate estimate, you should think of an algorithm that takes into account variables specific to your application, such as the type of the SQL statement that is executed, or the complexity of the parsed document's XML schema.

Summary

The web application of this article has shown you how easy is to implement a progress bar based on JSP, Java, HTML, and JavaScript. The hard part is to integrate it within existing real applications, taking into account the issues described above. There is no general integration solution. Each real heavy task needs to be analyzed separately.

Resources

Andrei Cioroianu is the founder of Devsphere and an author of many Java articles published by ONJava, JavaWorld, and Java Developer's Journal.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值