Java Language Best Practices to fallow so that application will be efficient.

Java Language Best Practices



Many performance studies have shown a high performance cost in using synchronization in Java. Improper synchronization can also cause a deadlock, which can result in complete loss of service because the system usually has to be shut down and restarted.
 But performance overhead cost is not a sufficient reason to avoid synchronization completely. Failing to make sure your application is thread-safe in a multithreaded environment can cause data corruption, which can be much worse than losing performance.

 The following are some practices that you can consider to minimize the overhead:

  1. Synchronize Critical Sections Only
  2. Do Not Use the Same Lock on Objects That Are Not Manipulated Together
  3. Use Private Fields
  4. Use a Thread Safe Wrapper
  5. Use Immutable Objects
  6. Know Which Java Objects Already Have Synchronization Built-in
  7. Do Not Under-Synchronize

Monitor Synchronization

Java synchronization can cause a deadlock. The best way to avoid this problem is to avoid the use of Java synchronization. One of the most common uses of synchronization is to implement pooling of serially reusable objects. 


Often, you can simply add a serially reusable object to an existing pooled object. For example, you can add Java Database Connectivity (JDBC) and Statement object to the instance variables of a single thread model servlet, or you can use the Oracle JDBC connection pool rather than implement your own synchronized pool of connections and statements.


If you must use synchronization, you should either avoid deadlock, or detect it and break it. Both strategies require code changes. So, neither can be completely effective because some system code uses synchronization and cannot be changed by the application.


To prevent deadlock, simply number the objects that you must lock, and ensure that clients lock objects in the same order.
Proprietary JVM extensions may be available to help spot deadlocks without having to instrument code, but there are no standard JVM facilities for detecting deadlock.


Monitor and Fix Resource Leaks


One way to fix resource leaks is straightforward - a periodic restart. It provides good protection against slow resource leaks. But it is also important to spot applications that are draining resources too quickly, so that any software bugs can be fixed.

 Leaks that prevent continuous server operation for at least 24 hours must be fixed in the application code, not by application restart.


Common programming mistakes are:
  • Not returning the resource to the pool (or not removing it from the pool) after handling an error.
  • Relying on the garbage collector to invoke finalize() and free resources. Never rely on the garbage collector to manage any resource other than memory.
  • Not discarding old object references which prevent recycling the memory occupied by the objects.
Monitoring resource usage should be a combination of code instrumentation and external monitoring utilities. With code instrumentation, calls to an application-provided interface, or calls to a system-provided interface like Oracle Dynamic Monitoring System (DMS), are inserted at key points in the application's resource usage lifecycle. Done correctly, this can give the most accurate picture of resource use. Unfortunately, the same programming errors that cause resource leaks are also likely to cause monitoring errors. That is, you may forget to release the resource, or forget to monitor the release of the resource.


Operating system commands like vmstat or ps in UNIX, provide process-level information such as the amount of memory allocated, the number and state of threads, or number of network connections. They can be used to detect a resource leak. Some commercially available development tools can also be used to find the leak.
In addition to compromising availability, resource leaks and overuse decrease performance.

Always Use a Finally Clause In Each Method to Cleanup


In Java, it is impossible to leave the try or catch blocks (even with a throw or return statement) without executing the finally block. If for any reason the instance variables cannot be cleaned, throw a catch-all exception that should cause the caller to discard its object reference to this now corrupt object. 

If, for any reason the static variables cannot be cleaned, throw an InternalError or equivalent that will ultimately result in restarting the now corrupt JVM.


Discard Objects That Throw Catch-All Exceptions


In many cases, these exceptions indicate that the internal state of the invoked object is corrupt, and that further invocations will also fail. Keep the object reference only if careful scrutiny of the exception shows it is benign, and further invocations on this object are likely to succeed.


Adopt a guilty unless proven innocent approach. For example, a SQLException thrown from an Oracle JDBC invocation could represent one of thousands of error conditions in the JDBC driver, the network, or the database server. Some of these errors (for example, subclass SQLWarning) are benign. 

Some SQLExceptions (for example, "ORA-3113: end of file on communication channel") definitely leave the JDBC object useless. Most SQLExceptions do not clearly specify what state the JDBC object is left in. 

The best approach is to enumerate the benign error codes that could occur frequently in your application and can definitely be retried, such as a unique key violation for user-supplied input data. If any other error code is found, discard the potentially corrupt object that threw the exception.


Discard all object references to the (potentially) corrupt object. Be sure to remove the corrupt object from all pools in order to prevent pools from being poisoned by corrupt objects. Do not invoke the corrupt object again - instantiate a brandnew object instead.
When you are sure that the corrupt objects have been discarded and that the catching object is not corrupt, throw a non catch-all exception so that the caller does not discard this object

Design Transactions Usage Correctly

Transactions should not span client requests because this can tie up shared resources indefinitely.
Requests generally should not span more than one transaction, because a failure in mid-request could leave some transactions committed and others rolled back. If this requires application-level compensation to recover, then availability or data integrity may be compromised.
Transactions generally should not span more than one database, because distributed transactions lock shared resources longer, and failure recovery may require simultaneous availability and coordination of multiple databases.


Applications that require a single client request (for example, a confirm checkout request in a shopping cart application) to ultimately affect several databases (for example, credit card, fulfillment, shopping cart, and customer history databases) should perform the first step with one database, and in the same transaction queue a message in the first database addressed to the second database.

 The second database will perform the second step and queue the third step, and so on. This queued transaction chain will eventually complete automatically, or an administrator will see an undeliverable message and will have to manually compensate.


Put Business Logic In the Right Place

In general, you should not implement business logic in your client program. Instead, put validation and defaulting logic in your entity objects, and put client-callable methods in application modules, view objects, and view rows.


Working with application module methods allows the client program to encapsulate task-level custom code in a place that allows data-intensive operations to be done completely in the middle-tier without burdening the client.


Working with view object methods allows the client program to access the entire row collection for cross-row calculations and operations.
Working with view row methods allows the client program to operate on individual rows of data. There are three types of custom view row methods you may want to create:
  • Accessor methods: The oracle.jbo.Row interface (which view rows implement) contains the methods getAttribute() and setAttribute(), but these methods are not typesafe. You can automatically generate custom typesafe accessors when you generate a custom view row class.
  • Delegators to entity methods: By design, clients cannot directly access entity objects. If you want to expose an entity method to the client tier, you should create a delegator method in a view row.
  • Entity-independent calculations: This is useful if the calculation uses attributes derived from multiple entity objects or from no entity objects.

Avoid Common Errors That Can Result In Memory Leaks

In Java, memory bugs often appear as performance problems, because memory leaks usually cause performance degradation. Because Java manages the memory automatically, developers do not control when and how garbage is collected. To avoid memory leaks, check your applications to make sure they:
  • Release JDBC ResultSet, Statement, or connection.
  • Release failures here are usually in error conditions. Use a finally block to make sure these objects are released appropriately.
  • Release instance or resource objects that are stored in static tables.
Perform clean up on serially reusable objects.
An example is appending error messages to a Vector defined in a serially reusable object. The application never cleaned the Vector before it was given to the next user. As the object was reused over and over again, error messages accumulated, causing a memory leak that was difficult to track down.

Avoid Creating Objects or Performing Operations That May Not Be Used

This mistake occurs most commonly in tracing or logging code that has a flag to turn the operation on or off during runtime. 

Some of this code goes to great lengths creating and formatting output without checking the flag first, creating many objects that are never used when the flag is off. This mistake can be quite expensive, because tracing and logging usually involves many String objects and operations to translate the message or even access to the database to retrieve the full text of the message.

 Large numbers of debug or trace statements in the code make matters worse.

Replace Hashtable and Vector With Hashmap, ArrayList, or LinkedList If Possible

The Hashtable and Vector classes in Java are very powerful, because they provide rich functions. Unfortunately, they can also be easily misused. Since these classes are heavily synchronized even for read operations, they can present some challenging problems in performance tuning. Hence, the recommendations are:
  • Use an Array Instead of an ArrayList If the Size Can Be Fixed
  • Use an ArrayList or LinkedList To Hold a List of Objects In a Particular Sequence
  • Use HashMap or TreeMap To Hold Associated Pairs of Objects
  • Replace Hashtable, Vector, and Stack
  • Avoid Using String As the Hash Key (If Using JDK Prior to 1.2.2)

Reuse Objects Instead of Creating New Ones If Possible

Object creation is an expensive operation in Java, with impact on both performance and memory consumption. The cost varies depending on the amount of initialization that needs to be performed when the object is to be created. Here are ways to minimize excess object creation and garbage collection overhead:
  • Use a Pool to Share Resource Objects
  • Recycle Objects
  • Use Lazy Initialization to Defer Creating the Object Until You Need It.

Use Stringbuffer Instead of String Concatenation

The String class is the most commonly used class in Java. Especially in Web applications, it is used extensively to generate and format HTML content.
String is designed to be immutable; in order to modify a String, you have to create a new String object. 

Therefore, string concatenation can result in creating many intermediate String objects before the final String can be constructed. StringBuffer is the mutable companion class of String; it allows you to modify the String. Therefore, StringBuffer is generally more efficient than String when concatenation is needed.


This section also features the following practices:
  1. Use StringBuffer Instead of String Concatenation If You Repeatedly Append to a String In Multiple Statements
  2. Use Either String or StringBuffer If the Concatenation Is Within One Statement
  3. Use StringBuffer Instead of String Concatenation If You Know the Size of the String


Comments

  1. Just providing points such way does not make any sense...

    ReplyDelete
  2. Today will explain all dont worry rishi

    ReplyDelete
  3. Today will explain all dont worry rishi

    ReplyDelete

Post a Comment