Don't use SingleThreadModel. Make the servlet thread-safe, but try to minimize the amount of time spent in synchronized code while still maintaining a thread-safe servlet.
Use as many servlet threads as necessary to handle the request throughput. Use resource pools to distribute resources among the servlet threads.
The amount of data sent in the first network packet is crucial to optimal performance. Send the response headers and the first load of data as a single packet instead of two separate packets.
Use StringBuffers or other efficient String or byte array-building mechanisms. Avoid generating intermediate Strings and other objects whenever possible. Avoid the + and += concatenation operators.
Use the browser's caching mechanism to have pages reread by correctly implementing the getLastModified( ) method.
Precalculate all static formatting for generated HTML pages. High-volume web applications prerender pages that are the same for all users.
Use the include directive rather than the include action.
Minimize the useBean action's scope to page where possible.
Remember that redirects (using sendRedirect( )) are slower than forwards (<jsp:forward ...>).
Use cache tags (see, for example, http://www.opensymphony.com/oscache/).
Avoid creating HttpSession objects if not needed, and time out HttpSessions when they are needed.
"Context" has a much wider scope than "session." Use HttpSession methods for session resources.
Avoid having HttpSession objects serialized by the servlet container. Remove HttpSession objects explicitly with HttpSession.invalidate( ) when the session is finished, such as when the user logs out.
Implement the HttpSessionBindingListener for any resources that need to be cleaned up when sessions terminate, and explicitly release resources in the valueUnbound( ) method.
The servlet init( ) and destroy( ) or jspInit( ) and jspDestroy( ) methods are ideal for creating and destroying limited and expensive resources, such as cached objects and database connections.
Compress output if the browser supports displaying compressed pages.
Avoid reverse DNS lookups.
Precompile your JSPs.
Use Servlet 2.3 application and session events to make the application event-driven.
Remember that servlet filters have overhead associated with the filter mechanism.
Validate data at the client if it can be done efficiently.
Increase server TCP/IP listen queues.
Disable autoreloading features that periodically reload servlets and JSPs.
Tune the pool sizes in the server.
Transform your data to minimize the costs of searching it.