I. GENERAL articles The "general article" discussion issues are appropriate for most Java applications. 1.1 Create an instance of the class without the new keyword When you create an instance of a class with the new keyword, all constructors in the constructor chain are automatically called. But if an object implements the Cloneable interface, we can call its clone () method. The Clone () method does not call any class constructors. When using the design pattern, creating a new object instance using the Clone () method is straightforward if you create the object in Factory mode. For example, here is a typical implementation of the factory pattern: public static Credit Getnewcredit () { return new credit (); } The improved code uses the Clone () method, as follows: private static Credit Basecredit = new Credits (); public static Credit Getnewcredit () { return (Credit) Basecredit.clone (); } The idea above is also useful for array processing. 1.2 Using non-blocking I/O A lower version of the JDK does not support the nonblocking I/O API. To avoid I/O blocking, some applications use a method of creating a large number of threads (in better cases, a buffer pool is used). This technology can be seen in many applications that must support concurrent I/O flows, such as Web servers, quotes, and auction applications. However, creating a Java thread requires considerable overhead. JDK 1.4 introduces a non-blocking I/O library (Java.nio). If your application requires an earlier version of the JDK, there is a package that supports non-blocking I/O. See "Tuning Java I/O performance" on the Sun China website. 1.3 Caution with exceptions Exceptions are bad for performance. Throwing an exception begins with creating a new object. The constructor of the Throwable interface calls the local (Native) method named Fillinstacktrace (), the Fillinstacktrace () method examines the stack, and collects the call trace information. Whenever an exception is thrown, the VM must adjust the call stack because a new object is created during processing. Exceptions can only be used for error handling and should not be used for control procedures. 1.4 Do not repeat initialization of variables By default, when invoking the constructor of a class, Java initializes the variable to a deterministic value: All objects are set to NULL, integer variables (byte, short, int, long) are set to 0,float and double variables are set to 0.0, and the logical value is set to False. This is especially important when a class is derived from another class, because all constructors in the constructor chain are called automatically when an object is created with the new keyword. 1.5 Specify the final modifier of the class as much as possible A class with a final modifier is not derived. In the Java Core API, there are many examples of final applications, such as java.lang.String. Specifying final for the string class prevents people from overwriting the length () method. In addition, if you specify a class to be final, all methods of that class are final. The Java compiler looks for the opportunity Inline (inline) for all final methods (this is related to the specific compiler implementation). This will increase the performance by an average of 50%. 1.6 Use local variables as much as possible The parameters passed when the method is called and the temporary variables created in the call are saved in the stack, which is faster. Other variables, such as static variables, instance variables, and so on, are created in the heap and are slower. Also, depending on the compiler/JVM, local variables may be further optimized. See Use stack variables whenever possible. 1.7 Multiplication and division Consider the following code: for (val = 0; Val < 100000; Val +=5) {Alterx = val * 8; myresult = val * 2;} Replacing multiplication operations with shift operations can greatly improve performance. The following is the modified code: for (val = 0; Val < 100000; val + = 5) {Alterx = Val << 3; myresult = Val << 1;} The modified code does not multiply by 8, but instead shifts to the equivalent left-shifted 3-bit operation, with each left shift of 1 bits equal to 2 times. Accordingly, the right-shift 1-bit operation is equivalent to dividing by 2. It is worth mentioning that although the shift operation is fast, but may make the code more difficult to understand, so it is best to add some comments. 2 back top Second, the EE chapter The improved performance techniques described earlier are appropriate for most Java applications, and the next issue to be discussed is for applications that use JSP, EJB, or JDBC. 2.1 Using buffer Markers Some application servers have joined the JSP-oriented buffer tagging feature. For example, BEA's WebLogic server supports this feature from version 6.0, and the Open Symphony Project also supports this feature. The JSP buffer tag can buffer the page fragment as well as the entire page. When the JSP page executes, if the target fragment is already in the buffer, the code that generated the fragment is no longer executed. Page-level buffering captures requests for a specified URL and buffers the entire result page. This feature is extremely useful for shopping baskets, catalogs, and the homepage of the portal site. For such applications, page-level buffering can save the results of page execution for subsequent requests to use. For pages with complex code logic, the effect of using buffer tags for high performance is obvious; Conversely, the effect may be slightly less. See improving performance and stability of JSP applications with buffering technology. 2.2 Entity beans are always accessed through session beans Direct access to entity beans is detrimental to performance. When the client program accesses the entity bean remotely, each get method is a remote call. The session bean that accesses the entity bean is local, can organize all the data into a structure, and then returns its value. Encapsulating access to entity beans with session beans improves transaction management because session beans are committed only when they reach the transaction boundary. Each direct call to the Get method produces a transaction in which the container performs a mount-read operation after each entity Bean's transaction. In some cases, using entity beans can cause poor program performance. If the only purpose of an entity bean is to extract and update data, it can be better to use JDBC to access the database within the session bean. 2.3 Choosing the appropriate reference mechanism In a typical JSP application system, the page header, footer section is often extracted, and then as needed to introduce the page header, footer. Currently, there are two main ways to introduce external resources into JSP pages: include directives, and include actions. Include directives: For example, <%@ include file= "copyright.html"%>. The directive introduces the specified resource at compile time. Before compiling, the page with the include directive and the specified resource are merged into a single file. The referenced external resources are determined at compile time, and the resource is more efficient than the runtime. Include action: For example <jsp:include page= "copyright.jsp"/>. This action introduces the results generated after the specified page executes. Because it completes at run time, the control of the output results is more flexible. However, using the include action is only advantageous when the referenced content changes frequently, or if the referenced page cannot be determined until a request to the main page is not present. 2.4 Setting read-only properties in the deployment descriptor The deployment descriptor of the entity Bean allows all get methods to be set to read-only. Setting a read-only property improves performance when the work of a transaction unit contains only the method that performs the read operation, because the container no longer has to perform the storage operation. 2.5 buffering access to the EJB home The EJB home interface is obtained through Jndi name lookups. This operation requires considerable overhead. Jndi lookups are best placed inside the servlet's init () method. If EJB access occurs frequently in multiple applications, it is a good idea to create a Ejbhomecache class. The Ejbhomecache class should generally be implemented as a singleton. 2.6 Implementing a local interface for EJBS The local interface is what's new in the EJB 2.0 specification, which allows the bean to avoid the overhead of remote calls. Please consider the following code. Paybeanhome home = (paybeanhome) Javax.rmi.PortableRemoteObject.narrow (Ctx.lookup ("Paybeanhome"), Paybeanhome.class); Paybean bean = (paybean) Javax.rmi.PortableRemoteObject.narrow (Home.create (), paybean.class); The first statement indicates that we are looking for the bean's home interface. This lookup is done through Jndi, which is an RMI call. We then locate the remote object, returning the proxy reference, which is also an RMI call. The second statement demonstrates how to create an instance that involves a stub program that creates a IIOP request and transmits the request over the network, which is also an RMI call. To implement the local interface, we must make the following modifications: The Java.rmi.RemoteException method can no longer throw an exception, including exceptions derived from remoteexception, such as Transactionrequiredexception, Transactionrolledbackexception and Nosuchobjectexception. EJB provides an equivalent local exception, such as Transactionrequiredlocalexception, Transactionrolledbacklocalexception and Nosuchobjectlocalexception. All data and return values are passed by reference, not by passing values. The local interface must be used on the EJB deployed machine. In short, the client program and the component that provides the service must run on the same JVM. If the bean implements a local interface, its references are not serializable. See increasing the efficiency of EJB access with local references. 3 back top 2.7 Generating a primary key There are many ways to generate a primary key within an EJB, and here are a few common approaches and their characteristics. Leverage the built-in identity mechanism of the database (the identity of SQL Server or Oracle's sequence). The disadvantage of this approach is that EJB portability is poor. The primary key values (such as incremental operations) are computed by the entity bean itself. Its disadvantage is that it requires transactions to be serializable and slower. Use a clock service like NTP. This requires a specific platform-oriented local code that secures the bean to a specific OS. In addition, it also leads to the possibility that two primary keys are generated in the same millisecond on a multi-CPU server. Draw on Microsoft's ideas and create a GUID in the bean. However, if you do not turn to Jni,java, you cannot determine the MAC address of the NIC, and if you use JNI, the program relies on a particular OS. There are several other options, but these approaches also have their own limitations. It seems that only one answer is ideal: using RMI and Jndi together. The RMI remote object is bound to the Jndi tree first through RMI registration. The client program searches through Jndi. Here is an example: public class Keygenerator extends UnicastRemoteObject implements Remote { private static Long KeyValue = System.currenttimemillis (); public static synchronized Long GetKey () throws remoteexception {return keyvalue++;} 2.8 Timely removal of sessions that are no longer needed In order to clear a session that is no longer active, many application servers have a default session timeout, which typically takes 30 minutes. When the application server needs to save more sessions, if the memory capacity is insufficient, the operating system will transfer some of the memory data to disk, and the application server may dump some inactive sessions to disk based on the most recently used (most recently used) algorithm, and may even throw "out of memory" Abnormal. In large-scale systems, the cost of serialization sessions is expensive. When the session is no longer needed, the Httpsession.invalidate () method should be called in time to clear the session. The Httpsession.invalidate () method can usually be called on an app's exit page. 2.9 Closing useless sessions in a JSP page For those pages that do not need to track session state, turning off automatically created sessions can save some resources. Use the following page directive: <%@ page session= "false"%> 2.10 Servlet and Memory usage Many developers randomly save a lot of information to a user session. At some point, objects saved in the session are not reclaimed in a timely manner by the garbage collection mechanism. From a performance perspective, the typical symptom is that the user feels that the system is periodically slowing down, but cannot attribute the cause to any specific component. If you monitor the JVM's heap space, it behaves as if the memory usage is abnormally steep and steep. There are two main ways to solve this type of memory problem. The first approach is to implement the Httpsessionbindinglistener interface in all beans scoped to the session. This allows the resources used by the bean to be explicitly freed as long as the Valueunbound () method is implemented. Another option is to invalidate the session as quickly as possible. Most application servers have the option to set the session deprecation interval. Alternatively, you can programmatically invoke the session's Setmaxinactiveinterval () method, which is used to set the maximum interval of time, in seconds, that the servlet container allows for client requests before the session is invalidated. 2.11 HTTP keep-alive The keep-alive feature makes the client-to-server connection persistent, and when a subsequent request to the server occurs, the Keep-alive feature avoids establishing or re-establishing the connection. Most Web servers on the market, including Iplanet, IIS, and Apache, support HTTP keep-alive. This feature is often useful for websites that provide static content. However, there is another problem with heavier sites: while retaining open connections for customers has some benefits, it also affects performance because the resources that could have been freed during the processing pause are still occupied. When the Web server and application server are running on the same machine, the Keep-alive feature has a particularly significant impact on resource utilization. 2.12 JDBC and Unicode Presumably you already know some of the things that improve performance when using JDBC, such as using connection pooling, correctly selecting stored procedures and directly executing SQL, removing redundant columns from result sets, precompiled SQL statements, and so on. In addition to these obvious choices, another good choice for high performance might be to save all character data as Unicode (code page 13488). Java processes all data in Unicode, so the database driver no longer has to perform the conversion process. However, it should be remembered that if this is the case, the database will become larger because each Unicode character requires 2 bytes of storage space. Additionally, if there are other non-Unicode programs accessing the database, the performance issue still occurs because the database driver still has to perform the conversion process. 2.13 jdbc and I/O If your application needs to access a large data set, you should consider using block extraction. By default, JDBC extracts 32 rows of data at a time. For example, if we were to traverse a 5000-row recordset, JDBC had to call the database 157 times to fetch all the data. If you change the block size to 512, the number of times the database is called will be reduced to 10 times. In some cases this technique is ineffective. For example, if you use a scrollable recordset, or if you specify a for UPDATE in a query, the block operation is no longer valid. 2.14 In-memory database Many applications need to store a significant amount of data in the session object, typically such as shopping baskets and catalogs, in a user-based organization. Since such data can be organized in rows/columns, many applications create large vectors or hashmap. Saving this type of data in a session greatly limits the scalability of the application because the server has at least the amount of memory consumed by each session multiplied by the maximum number of concurrent users, which not only makes the server expensive, but also can extend the time interval for garbage collection to intolerable levels. Some people have shifted the shopping basket/directory functionality to the database tier, which has improved scalability to some extent. However, there are problems in putting this part of the functionality into the database layer, and the root cause of the problem is related to the architecture of most relational database systems. For relational databases, one of the important principles of the runtime is to ensure that all writes are stable and reliable, so all performance issues are related to the ability to physically write data to disk. Relational databases attempt to reduce I/O operations, especially for read operations, but the main way to achieve this is to execute a set of complex algorithms that implement the buffering mechanism, which is the main reason why the first performance bottleneck in the database tier is always CPU-bound. One alternative to traditional relational databases is to use databases running in memory (In-memory database), such as TimesTen. The starting point of the in-memory database is to allow data to be written temporarily, but the data does not have to be persisted to disk, and all operations are performed in memory. In this way, the memory database does not require complex algorithms to reduce I/O operations, and it can adopt a relatively simple locking mechanism, so it is very fast. 4 back top Third, GUI article This section describes the content for graphical user interface applications (applets and general applications), using AWT or swing. 3.1 Compressing a class file with a jar Java Archive files (jar files) are files that are compressed according to the JavaBean Standard and are the primary way and recommended way to publish JavaBean components. Jar Archives help reduce file volume and shorten download time. For example, it helps applets increase startup speed. A jar file can contain one or more related beans as well as supporting files, shapes, sounds, HTML, and other resources. To specify a jar file in the html/jsp file, simply include the archive = "Name.jar" declaration in the applet tag. See increasing the loading speed of applets with an archive file. 3.2 Tip Applet loading process Have you ever seen a website that uses applets, and notice that a placeholder appears where the applet should run? What happens when an applet is downloaded for a long time? The biggest possibility is that users turn around and leave. In this case, displaying information that an applet is downloading will undoubtedly help encourage the user to continue waiting. Let's take a look at a specific implementation method. Start by creating a small applet that is responsible for downloading the official applets in the background: Import Java.applet.Applet; Import java.applet.AppletStub; Import Java.awt.Label; Import Java.awt.Graphics; Import Java.awt.GridLayout; public class Preloader extends Applet implements Runnable, Appletstub { String Largeappletname; Label label; public void init () { Formal applets requiring loading Largeappletname = GetParameter ("applet"); "Please wait" prompt message Label = new label ("Please wait ..." + largeappletname); Add (label); } public void Run () { try { class to get the applet to be loaded Class Largeappletclass = Class.forName (largeappletname); Create an instance of the applet to be loaded Applet Largeapplet = (applet) largeappletclass.newinstance (); Set the stub program for the Applet Largeapplet.setstub (this); Cancel "Please wait" information Remove (label); Set layout SetLayout (New GridLayout (1, 0)); Add (Largeapplet); Show the Official applet Largeapplet.init (); Largeapplet.start (); } catch (Exception ex) { Display error message Label.settext ("cannot fit the specified applet"); } Refresh Screen Validate (); } public void appletresize (int width, int height) { Passing the Appletresize call from the stub program to the Applet Resize (width, height); } } The compiled code is less than 2K and the download speed is fast. There are several places in the code that deserve attention. First, the Preloader implements the Appletstub interface. In general, applets judge their codebase from the caller. In this case, we must call Setstub () to tell the applet where to extract this information. Another notable point is that the Appletstub interface contains many of the same methods as the Applet class, except for the Appletresize () method. Here we pass the call to the Appletresize () method to the Resize () method. 5 back top 3.3 Pre-load the graphic before drawing it The ImageObserver interface can be used to receive prompt information for graphics loading. The ImageObserver interface has only one method, Imageupdate (), capable of drawing graphics on the screen with a single repaint () operation. An example is provided below. public boolean imageupdate (Image img, int flags, int x, int y, int w, int h) { if ((Flags & allbits)!=0 { Repaint (); } else if (Flags & (ERROR | ABORT))! = 0) { Error = TRUE; File not found, consider displaying a placeholder Repaint (); } Return (Flags & Allbits | error| ABORT) = = 0; } The Imageupdate () method is called when the graphics information is available. If further updates are required, the method returns True, and if the required information has been obtained, the method returns false. 3.4 Overriding the Update method The default action of the update () method is to clear the screen and then call the paint () method. If you use the default update () method, applications that use graphics frequently may display flicker. To avoid screen cleanup before the paint () call, simply overwrite the update () method as follows: public void Update (Graphics g) { Paint (g); } A more desirable scenario would be to overwrite update () and redraw only the area that changed on the screen, as shown below: public void Update (Graphics g) { G.cliprect (x, Y, W, h); Paint (g); } 3.5 Delay Redraw Operation For graphical user interface applications, the main reason for poor performance can often be attributed to the inefficiency of the painting screen. This is usually noticeable when the user changes the window size or scrolls through a window. Changing the size of the window or scrolling the screen causes the redrawing of the screen event to be generated massively, quickly, or even faster than the execution of the associated code. The best way to deal with this problem is to ignore all "late" events. It is recommended to introduce a millisecond difference here, that is, if we immediately receive another redraw event, we can stop processing the current event to handle the last received redraw event, otherwise we proceed with the current redraw process. If an event is to start a time-consuming task, separating out a worker thread is a good way to handle it; otherwise, some parts may be "Frozen" because only one event can be processed at a time. A simple example of event handling is provided below, but it can be used to control the worker thread after it has been expanded. public static void RunOnce (String ID, final long milliseconds) { Synchronized (e_queue) {//E_queue: Collection of all events if (!e_queue.containskey (ID)) { E_queue.put (token, new LaStone ()); } } Final LaStone LaStone = (lastone) e_queue.get (token); Final long time = System.currenttimemillis (); Get current time Lastone.time = time; (New Thread () {public void run () { if (milliseconds > 0) { try {thread.sleep (milliseconds);}//Pause thread catch (Exception ex) {} } Synchronized (lastone.running) {//wait for last event to end if (lastone.time! = time)//handle only the last event Return } }}). Start (); } private static Hashtable E_queue = new Hashtable (); private Static Class LaStone { public long time=0; public object running = new Object (); } 6 back top 3.6 Using double buffers Draw the buffer outside the screen and display the entire graphic immediately after it is finished. Since there are two buffers, the program can switch back and forth. In this way, we can use a low-priority thread for drawing, which allows the program to take advantage of the idle CPU time to perform other tasks. The following pseudo-code fragment demonstrates this technique. Graphics Mygraphics; Image myoffscreenimage = createimage (Size (). width, size (). height); Graphics offscreengraphics = Myoffscreenimage.getgraphics (); Offscreengraphics.drawimage (IMG, +, this); Mygraphics.drawimage (myoffscreenimage, 0, 0, this); 3.7 Using BufferedImage Java JDK 1.2 uses a soft display device that makes the text look similar on different platforms. To achieve this, Java must directly handle the pixels that make up the text. Since this technique is used to perform a large amount of bit-copying operations in memory, the early JDK has poor performance when using this technology. The Java standard proposed to solve this problem implements a new type of graph, namely bufferedimage. The graphics described by the BufferedImage subclass have an accessible graphics data buffer. A bufferedimage contains a ColorModel and a set of raster graphic data. This class generally uses the RGB (red, green, blue) color model, but it can also handle grayscale graphics. Its constructor is simple, as follows: public bufferedimage (int width, int height, int imageType) ImageType allows us to specify what types of graphics to buffer, such as 5-bit RGB, 8-bit RGB, grayscale, and so on. 3.8 Using Volatileimage Many hardware platforms and their operating systems provide basic hardware acceleration support. For example, hardware acceleration typically provides a rectangular fill feature, and hardware acceleration is more efficient than using the CPU to accomplish the same task. Because hardware acceleration separates part of the work, it allows multiple workflows to be concurrent, easing the pressure on the CPU and the system bus, allowing applications to run faster. With Volatileimage, you can create hardware-accelerated graphics and manage the content of graphics. Due to its ability to directly utilize the low-level platform, the performance improvement depends primarily on the graphics adapter used by the system. The content of Volatileimage may be lost at any time, i.e. it is "unstable (volatile)". Therefore, it is a good idea to check if the content is missing before using the graphic. Volatileimage has two ways to check if the content is missing: public abstract int Validate (graphicsconfiguration GC); Public abstract Boolean contentslost (); You should call the Validate () method each time you copy content from a Volatileimage object or write to Volatileimage. The Contentslost () method tells us whether the contents of the graphic have been lost since the last validate () call. Although Volatileimage is an abstract class, do not derive subclasses from it. Volatileimage should be created through the component.createvolatileimage () or Graphicsconfiguration.createcompatiblevolatileimage () method. 3.9 using Window blitting When scrolling, all visible content is generally redrawn, resulting in a lot of unnecessary redrawing work. Many operating system graphics subsystems, including WIN32 GDI, MacOS, and x/windows, Support window blitting technology. Window blitting Technology moves the graphic to a new location directly in the screen buffer, redrawing only the newly emerging area. To use window blitting technology in a swing application, set the method as follows: Setscrollmode (int mode); In most applications, using this technique can improve scrolling speed. Only in one scenario, Window blitting can cause performance degradation, that is, the app scrolls in the background. If the user is scrolling an app, then it is always in the foreground without worrying about any negative effects. |