Java programing considering performance

1,599 views

Published on

Java programing considering performance

Published in: Technology
0 Comments
11 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,599
On SlideShare
0
From Embeds
0
Number of Embeds
37
Actions
Shares
0
Downloads
0
Comments
0
Likes
11
Embeds 0
No embeds

No notes for slide

Java programing considering performance

  1. 1. Java programming considering performance Roger Xia 2008-05
  2. 2. <ul><li>Effective Java 2nd Edition (Joshua Bloch) </li></ul><ul><li>http://www.javaperformancetuning.com/tips/index.shtml </li></ul>
  3. 3. General idea
  4. 4. Considerations <ul><li>Do you know Java </li></ul><ul><li> -- pay more attention to code convention </li></ul><ul><li> -- Java API : 1.3  1.4  1.5 </li></ul><ul><li> -- data structure & algorithm </li></ul><ul><li>Business Requirements </li></ul><ul><li> -- what is the requirements </li></ul><ul><li> -- future </li></ul><ul><li>Analyze and Design </li></ul><ul><li> -- Object oriented (encapsulation, inheritance, polymorphism) </li></ul><ul><li> -- Design pattern </li></ul><ul><li> -- RUP/UML </li></ul><ul><li> -- TDD </li></ul>
  5. 5. Java API <ul><li>It is better to read JDK source code than listen to others. </li></ul><ul><li>How java realizes collections, like HashMap? Hash, rehash? </li></ul><ul><li>How does Vector or ArrayList increase its capacity? </li></ul><ul><li>Why ConcurrentModificationException? </li></ul><ul><li>How to reverse a String in Java? </li></ul><ul><li>Do you know NIO? Since jdk1.4. What can NIO do for us? </li></ul><ul><li>Design pattern in java API. </li></ul>
  6. 6. Pool valuable system resources <ul><li>like threads, database connections, socket connections etc. </li></ul><ul><li>Optimize the pool sizes based on system and application specifications and requirements. </li></ul>
  7. 7. <ul><li>1). Use buffering when writing to and reading from files and/or streams. </li></ul><ul><li>Instead of reading a character or a byte at a time, the code with buffering can be improved further by reading one line at a time: </li></ul><ul><li>FileReader fr = new FileReader(f); </li></ul><ul><li>BufferedReader br = new BufferedReader(fr); </li></ul><ul><li>while (br.readLine()!=null) count ++; </li></ul><ul><li>It is recommended to use logging frameworks like Log4J or apache commons logging , which uses buffering instead of using default behaviour of System.out.println(…..) for better performance. </li></ul><ul><li>2). Make use of the performance and scalability enhancing features such as non-blocking and asynchronous I/O, mapping of file to memory etc offered by the NIO. </li></ul><ul><li>3). Where applicable caching can be used to improve performance by reading in all the lines of a file into a Java collection class like an ArrayList or a HashMap and subsequently access the data from an in-memory collection instead of the disk </li></ul>Optimize your I/O operations
  8. 8. Minimize network overheads <ul><li>Remote method invocations involve a network round-trip, marshalling and unmarshalling of parameters. </li></ul><ul><li>1). Retrieving several related items simultaneously in one remote invocation if possible. </li></ul><ul><li>2). Use effective design patterns </li></ul><ul><li>session façade </li></ul><ul><li>Improving performance by minimising fine-grained method calls over the network. </li></ul><ul><li>Improving manageability by reducing coupling, exposing uniform interface and exposing fewer methods to clients. </li></ul><ul><li>Managing transaction and security in a centralised manner. </li></ul><ul><li>value object </li></ul><ul><li>Avoid fine-grained method calls by creating a value object, which will help the client, make a coarsegrained call. </li></ul><ul><li>fast-lane reader pattern for database access </li></ul><ul><li>Access the persistent data directly from the database using the DAO (Data Access Object) pattern instead of using Entity beans. The Fast lane readers commonly use JDBC, Connectors etc to access the read-only data from the data source. The main benefit of this pattern is the faster data retrieval. </li></ul><ul><li>caching of received JNDI InitialContexts, factory objects </li></ul><ul><li>service locator which reduces expensive JNDI access with help of caching strategies. </li></ul>
  9. 9. Manage your objects efficiently <ul><li>Reuse objects where possible. It is cheaper to recycle objects than creating new objects each time. </li></ul><ul><li>Use mutable StringBuffer/StringBuilder classes instead of immutable String objects in computation expensive loops. </li></ul><ul><li>Automatic garbage collection: creating and destroying objects occupies a significant chunk of the JVM’s time. </li></ul><ul><li>1). If repeating code within a loop, avoid creating new objects for each iteration. Create objects before entering the loop (i.e. outside the loop) and reuse them if possible. </li></ul><ul><li>2). For complex objects that are used frequently, consider creating a pool of recyclable objects rather than always instantiating new objects. </li></ul><ul><li>3). Use lazy initialization when you want to distribute the load of creating large amounts of objects. Use lazy initialization only when there is merit in the design. </li></ul>
  10. 10. Performance tips <ul><li>Use ArrayList, HashMap etc as opposed to Vector, Hashtable etc (synchronized) where possible. Even better is to use just arrays where possible. </li></ul><ul><li>Set initial capacity of a collection (e.g. ArrayList, HashMap) and StringBuffer/StringBuilder appropriately. </li></ul><ul><li>Minimize the use of casting or runtime type checking like instanceof in frequently executed methods or in loops. Use visitor pattern to avoid “instanceof” construct. </li></ul><ul><li>Exception creation can be expensive because it has to create the full stack trace. If you are using your exception to just control the flow, then throw an exception, which is precreated. An efficient way to do this is to declare a public static final Exception in your exception class itself. </li></ul><ul><li>Avoid using System.out.println and use logging framework like Log4j etc, which use I/O buffers. </li></ul><ul><li>Minimize calls to Date, Calendar, etc related classes. </li></ul><ul><li>Applying multi-threading where applicable. </li></ul>
  11. 11. Detect and minimize potential memory leaks in Java <ul><li>In Java memory leaks are caused by poor program design where object references are long lived and the garbage collector is unable to reclaim those objects. </li></ul><ul><li>Use tools </li></ul><ul><li>Write your own utility class with help of totalMemory() and freeMemory() methods in Java Runtime class. </li></ul><ul><li>An even better approach than a utility class is using dynamic proxies or Aspect Oriented Programming for pre and post memory recording where you have the control of activating memory measurement only when needed. </li></ul>
  12. 12. Java performance analyze and design
  13. 13. Performance analyze <ul><li>JVM runtime load( 运行时负载 ) </li></ul><ul><ul><li>-- Bytecode executing </li></ul></ul><ul><ul><li>-- memory management </li></ul></ul><ul><ul><li>-- thread management </li></ul></ul><ul><ul><li>-- other operations </li></ul></ul><ul><li>JVM structure </li></ul><ul><ul><li>the memory layout of run-time data areas, </li></ul></ul><ul><ul><li>the garbage-collection algorithm used, </li></ul></ul><ul><ul><li>and any internal optimization of the Java virtual machine instructions </li></ul></ul>
  14. 14. <ul><li>Bytecode executing </li></ul><ul><li>JVM dynamically loads, links and initializes Bytecode of Class and Interface. </li></ul><ul><li>Loading , JVM finds the binary code which is the name of a special Class or Interface, it creates the Class or Interface in memory through the binary code. </li></ul><ul><li>Linking , link the Class or Interface with JVM runtime </li></ul><ul><li>Initialize , execute initialize method of the Class </li></ul>
  15. 15. <ul><li>Memory management </li></ul><ul><li>Most of the part in JVM memory are objects. </li></ul><ul><li>Memory of Object are allocated from heap. </li></ul><ul><li>Memory of Object are recycled by Garbage collector. </li></ul>
  16. 16. <ul><li>Thread management </li></ul><ul><li>Each thread has its own working memory. </li></ul><ul><li>Shared variables between threads are stored in the JVM’s main memory. </li></ul><ul><li>Synchronization of data between threads use lock to share data and keep data concurrency. </li></ul><ul><li>Transition of control between threads are realized by using wait, notify </li></ul>
  17. 17. <ul><li>JVM </li></ul><ul><li>Java memory allocation -- stack & heap </li></ul><ul><li>Stack: Each thread has a private stack ( thread safe ), which stores frames. </li></ul><ul><li>Heap: The JVM has a heap that is shared among all threads ( not thread safe ). The heap is the runtime data area from which memory for all class instances and arrays is allocated. It also has instance variables and method area. The heap is created on virtual machine start-up . Heap storage for objects is reclaimed by an automatic storage management system (known as a garbage collector ); objects are never explicitly deallocated. </li></ul><ul><li>Method Area: It is shared among all threads . It stores per-class structures such as the runtime constant pool, field and method code. It is logically part of the heap. Memory for class( static ) variables and methods declared in the class is also taken from it. </li></ul><ul><li>Runtime Constant Pool Or Constant Pool: It is a per-class or per-interface runtime representation of the constant_pool table . The JVM maintains a per-type constant pool, including literals (string, integer, and floating point constants). Each runtime constant pool is allocated from the JVM method area. </li></ul>
  18. 18. <ul><li>Frame Or Stack Frame </li></ul><ul><li>A frame is used to store data and partial results , as well as to perform dynamic linking , return values for methods, and dispatch exceptions . </li></ul><ul><li>A new frame is created each time a method is invoked and is destroyed when its method invocation completes, whether that completion is normal or abrupt (it throws an uncaught exception). </li></ul><ul><li>Frames are allocated from the JVM stack of the thread creating the frame. Each frame has its own array of local variables, its own operand stack , and a reference to the runtime constant pool of the class of the current method . </li></ul><ul><li>Only one frame , the frame for the executing method, is active at any point in a given thread of control . This frame is referred to as the current frame , and its method is known as the current method . The class in which the current method is defined is the current class . Operations on local variables and the operand stack are typically with reference to the current frame. </li></ul><ul><li>A frame ceases to be ( 不再是 ) current if its method invokes another method or if its method completes. When a method is invoked, a new frame is created and becomes current when control transfers to the new method. On method return, the current frame passes back the result of its method invocation, if any, to the previous frame. The current frame is then discarded as the previous frame becomes the current one. </li></ul>
  19. 21. <ul><li>Java Garbage Collection </li></ul><ul><li>&quot;memory recycling“, when an object is no longer referenced by the program, the heap space it occupies must be recycled so that the space is available for subsequent new objects. The garbage collector must somehow determine which objects are no longer referenced by the program and make available the heap space occupied by such unreferenced objects . In addition to freeing unreferenced objects, a garbage collector may also combat heap fragmentation . </li></ul><ul><li>If GC occurs too frequently, causes a lot of overhead </li></ul><ul><li>If GC doesn’t occur often enough, may run out of memory. </li></ul><ul><li>If GC takes too long to run </li></ul><ul><ul><li>Any requests coming in get suspended. </li></ul></ul><ul><li>If GC isn’t really cleaning up </li></ul><ul><ul><li>Storage creep, memory leak </li></ul></ul>
  20. 22. <ul><li>Object State in Memory </li></ul><ul><li>Created </li></ul><ul><li>In use (strongly reachable) </li></ul><ul><ul><li>Objects that are held by at least one strong reference are considered to be in use. </li></ul></ul><ul><li>Invisible </li></ul><ul><ul><li>An object is in the invisible state when there are no longer any strong references that are accessible to the program </li></ul></ul><ul><li>Unreachable </li></ul><ul><ul><li>An object enters an unreachable state when no more strong references to it exist. When an object is unreachable, it is a candidate for collection. </li></ul></ul><ul><li>Collected </li></ul><ul><ul><li>An object is in the collected state when the garbage collector has recognized an object as unreachable and readies it for final processing as a precursor to deallocation. If the object has a finalize method, then it is marked for finalization. </li></ul></ul><ul><li>Finalized </li></ul><ul><ul><li>An object is in the finalized state if it is still unreachable after its finalize method, if any, has been run. A finalized object is awaiting deallocation. </li></ul></ul><ul><li>Deallocated </li></ul><ul><ul><li>The deallocated state is the final step in garbage collection. </li></ul></ul>
  21. 23. <ul><li>Reach ability </li></ul><ul><li>Objects become garbage when they’re no longer reachable from the root set </li></ul><ul><li>The root set consists of: </li></ul><ul><ul><li>static reference fields in classes </li></ul></ul><ul><ul><li>Local reference variables within the method frames of each thread stack </li></ul></ul><ul><ul><li>The contents of the JVM’s root set changes dynamically a s </li></ul></ul><ul><ul><li>a). threads enter and exit methods, local reference variables come into and go out of scope (enter and leave the root set) </li></ul></ul><ul><ul><li>b). Elements within the root set directly refer to objects within the heap of the JVM </li></ul></ul><ul><ul><li>c). Reference variables within those objects refer to further objects within the Heap (indirectly reachable from the Root Set) </li></ul></ul>Unreachable Reachable Root Set
  22. 24. <ul><li>Generational Garbage Collection </li></ul><ul><li>Objects are allocated in a young generation, </li></ul><ul><ul><li>Because of infant mortality most objects die there. </li></ul></ul><ul><ul><li>When the young generation fills up it causes a minor collection. </li></ul></ul><ul><ul><li>The costs of minor collections are, to the first order, proportional to the number of live objects being collected. </li></ul></ul><ul><li>Surviving objects are moved to a tenured generation. </li></ul><ul><ul><li>When the tenured generation needs to be collected there is a major collection that is often much slower as it involves traversing all live objects </li></ul></ul><ul><li>Garbage collection occurs in each generation when the generation fills up. </li></ul>
  23. 25. <ul><li>New Object Region </li></ul><ul><li>The idea is to use a very fast allocation mechanism and hope that objects all become unreachable before garbage collection run </li></ul><ul><li>The New Object Regions is subdivided into three smaller regions: </li></ul><ul><ul><li>Eden, where objects are allocated </li></ul></ul><ul><ul><li>2 “Survivor” semi-spaces: “From” and “To” </li></ul></ul><ul><li>The Eden area is set up like a stack - an object allocation is implemented as a pointer increment </li></ul><ul><li>When the Eden area is full, the GC does a reachability test and then copies all the live objects from Eden to the “To” region </li></ul><ul><li>The labels on the regions are swapped </li></ul><ul><ul><li>“ To” becomes “From” - now the “From” area has objects </li></ul></ul><ul><li>The next time Eden fills objects are copied from both the “From” region and Eden to the “To” area </li></ul><ul><li>There’s a “Tenuring Threshold” that determines how many times an object can be copied between survivor spaces before it’s moved to the Old Object region </li></ul><ul><li>Note that one side-effect is that one survivor space is always empty </li></ul><ul><li>Old Object Region </li></ul><ul><li>The old object region is for objects that will have a long lifetime </li></ul><ul><li>The hope is that because most garbage is generated by short-lived objects that you won’t need to GC the old object region very often </li></ul>
  24. 26. Eden SS1 SS2 Old Eden SS1 SS2 Old Eden SS1 SS2 Old Eden SS1 SS2 Old First GC Second GC Eden SS1 SS2 Old New Object Region Old Object Region
  25. 27. <ul><li>Basic Algorithm </li></ul><ul><li>Reference counting : Keep a note on each object in your garage, indicating the number of live references to the object. If an object’s reference count goes to zero, collect the object. </li></ul><ul><li>Mark-Sweep : Put a note on objects you need (roots). Then recursively put a note on anything needed by a live object. Afterwards, check all objects and collect objects without notes. </li></ul><ul><li>Mark-Compact : Put notes on objects you need, move anything with a note on it to the back of the garage. Collect everything in front of the garage. </li></ul><ul><li>Copying : Move objects you need to a new garage. Then recursively move anything needed by an object in the new garage. Afterwards, burn down the old garage. </li></ul>
  26. 28. <ul><li>J2SE1.4 </li></ul><ul><li>the virtual machine incorporated number of different garbage collection algorithms that are combined using generational collection </li></ul><ul><li>Types of collectors in 1.4.x: </li></ul><ul><li>Serial Collector ( Default ) </li></ul><ul><li>-- single threaded </li></ul><ul><li>-- The young generation is divided into a creation space, often called Eden, and two survivor semi-spaces, using a copying collector . </li></ul><ul><li>-- A minor collection will copy live objects from Eden and one of the survivor semi-spaces into the other survivor space, potentially promoting some objects to the older generation. </li></ul><ul><li>-- A major collection will collect both the young and old generation. </li></ul><ul><li>-- The old generation uses a mark-compact collector </li></ul><ul><li>Throughput Collector </li></ul><ul><li>-- similar to the default collector </li></ul><ul><li>-- multiple threads used to do the minor collection </li></ul><ul><li>-- Can be enabled by using command line flag -XX:+UseParallelGC </li></ul><ul><li>-- The number of garbage collector threads can be controlled by - XX:ParallelGCThreads=<desired number>) </li></ul>
  27. 29. <ul><li>Concurrent Low Pause Collector </li></ul><ul><li>-- similar to the default collector, also multiple threads be used to do minor collection </li></ul><ul><li>-- Uses a separate garbage collector thread to do parts of the major collection concurrently with the applications threads. </li></ul><ul><li>-- The concurrent collector is enabled with the command line option -XX:+UseConcMarkSweepGC. </li></ul><ul><li>-- The concurrent collector pauses an application twice during a concurrent collection cycle. </li></ul><ul><ul><li>a). The first pause is to mark as live the objects. This first pause is referred to as the initial mark. </li></ul></ul><ul><ul><li>b). The second pause comes at the end of the marking phase and finds objects that were missed during the concurrent marking phase due to the concurrent execution of the application threads. The second pause is referred to as the remark. </li></ul></ul><ul><li>Incremental Low Pause Collector </li></ul><ul><li>-- The minor collections are done with the same young generation collector as the default collector. </li></ul><ul><li>-- The major collections are done incrementally on the tenured generation. </li></ul><ul><li>-- This collector collects portions of the tenured generation at each minor collection. </li></ul>
  28. 30. <ul><li>Adaptive Garbage Collection in J2SE 5.0 </li></ul><ul><li>J2SE 5.0 defines an adaptive sizing policy that will dynamically resize the heap and its respective regions with the following goals: </li></ul><ul><ul><li>Adhere to a desired maximum garbage collection pause </li></ul></ul><ul><ul><li>Adhere to a desired application throughput goal </li></ul></ul><ul><ul><li>Minimize the footprint of the heap </li></ul></ul><ul><li>Enable the adaptive sizing policy by passing the JVM -XX:+UseAdaptiveSizePolicy </li></ul><ul><li>Allows to set desire policy </li></ul><ul><ul><li>-XX:MaxGCPauseMillis=nnn </li></ul></ul><ul><ul><li>-XX:GCTimeRatio=nnn </li></ul></ul>
  29. 31. <ul><li>Reference </li></ul><ul><li>Apress -- Taming Java Threads </li></ul><ul><li>Java Virtual Machine Specification </li></ul><ul><li> -- http://java.sun.com/docs/books/vmspec/download/vmspec.2nded.html.zip </li></ul><ul><li>An introduction to the garbage-collected heap of the Java virtual machine </li></ul><ul><ul><li>http://www.javaworld.com/javaworld/jw-08-1996/jw-08-gc.html?page=1 </li></ul></ul><ul><li>GC Tuning Article </li></ul><ul><ul><li>http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html </li></ul></ul>
  30. 32. Performance design <ul><li>Construct object </li></ul><ul><li>When object can not get enough memory from heap, GC starts, recycle the memory allocated for objects whose reference count is 0. If GC failed to recycle the memory in time, memory leaks happens. </li></ul><ul><li>Creating new object not only cost CPU time and memory, but also cost much CPU time on continuously starting Garbage collector. </li></ul><ul><li>So avoid creating new object in frequency called codes. </li></ul>
  31. 33. <ul><li>Construct object </li></ul><ul><li>For collections, it’s better to initialize its capacity , or it will be set to a default value. If your requirement is bigger than the default value, JVM will recreate a new collection object and release the old one. </li></ul><ul><li>When many instances of a Class has a local variable to access a special object, it’s better to make the variable a static variable, rather than store a reference of the object in the variable of each instance. </li></ul><ul><li>Recycle container objects like Vector, Hashtable, etc rather than create new object and abandon old object. Do remember to release reference stored in container objects which refers to other objects. </li></ul><ul><li>Use primitive data type. </li></ul><ul><li>When just try to invoke a method of a class, do not create an object of the class, make the method a static method. </li></ul><ul><li>Simplify inheritance hierarchy of Class. Use component pattern and lazy load. </li></ul><ul><li>Design simple Constructor. </li></ul><ul><li>It is faster to create an array of primitive data type than to initialize such kind of array. </li></ul><ul><li>It is faster to create an array of complex data type than to clone such kind of array. </li></ul>
  32. 34. Best Practices to improve performance in Java programming
  33. 35. Performance improvement techniques in Object creation <ul><li>Object contains data and methods to manipulate the data. Whenever we create an object there is an overhead involved. </li></ul><ul><li>How object was created? </li></ul><ul><ul><li>When object t2 is created, the following steps are involved: </li></ul></ul><ul><ul><li>Memory is allocated to all the variables </li></ul></ul><ul><ul><li>All super class variables are also allocated memory </li></ul></ul><ul><ul><li>All sub class variables, super class variables are initialized. </li></ul></ul><ul><ul><li>The constructor is invoked. </li></ul></ul><ul><li>So whenever we create an object the above steps are repeated which take considerable resources so it is very important to decide whether creating a new object is required or not. </li></ul><ul><li>All objects are placed on heap, their address on the heap is stored in the stack. </li></ul><ul><li>All class variables are stored in the method area. </li></ul><ul><li>All primitive data types are stored on the stack. </li></ul>
  34. 36. Optimization techniques in Object creation <ul><li>Avoid creating objects in a loop . </li></ul><ul><li>Always try to use String literals instead of String objects . </li></ul><ul><li>Never create objects just for accessing a method. </li></ul><ul><li>Whenever you are done with an object make that reference null so that it is eligible for garbage collection. </li></ul><ul><li>Never keep inheriting chains long since it involves calling all the parent constructors all along the chain until the constructor for java.lang.Object is reached. </li></ul><ul><li>Use primitive data types rather than using wrapper classes . </li></ul><ul><li>Whenever possible avoid using class variables , use local variables since accessing local variables is faster than accessing class variables. </li></ul><ul><li>Use techniques such as lazy evaluation . Lazy evaluation refers to the technique of avoiding certain computations until they are absolutely necessary. This way we put off certain computations that may never need to be done at all. </li></ul><ul><li>Another technique is Lazy object creation : i.e. delaying the memory allocation to an object till it is not being put into use. This way a lot of memory is saved till the object is actually put in to use. </li></ul>
  35. 37. Performance improvement techniques in String and StringBuffer <ul><li>Overview of String and StringBuffer </li></ul><ul><li>Immutable objects cannot be modified once they are created. </li></ul><ul><li>Mutable objects can be modified after their creation. </li></ul><ul><li>String objects are immutable </li></ul><ul><li>StringBuffer objects are mutable. </li></ul><ul><li>You need to carefully choose between these two objects depending on the situation for better performance. </li></ul><ul><li>Better way of creating Strings </li></ul><ul><li>You can create String objects in the following ways. </li></ul><ul><li>1. String s1 = &quot;hello&quot;; String s2 = &quot;hello&quot;; </li></ul><ul><li>2. String s3 = new String(&quot;hello&quot;); String s4 = new String(&quot;hello&quot;); </li></ul><ul><li>Which of the above gives better performance? </li></ul><ul><li>First type of creation is much more faster than second type of creation, Why? </li></ul><ul><li>Because the content is same s1 and s2 refer to the same object </li></ul><ul><li>Where as s3 and s4 do not refer to the same object. </li></ul>
  36. 38. How the JVM works with Strings? <ul><li>JVM maintains an internal list of references for interned Strings ( pool of unique Strings) </li></ul><ul><li>When JVM loads String literal from class file and executes, it checks whether that String exists in the internal list or not. </li></ul><ul><li>But not for String object which it creates through 'new‘ keyword. </li></ul><ul><li>s1==s2 for the above code returns? </li></ul><ul><li>true </li></ul><ul><li>because s1 and s2 references point to the same object. </li></ul><ul><li>s3.equals(s4) for the above code returns? </li></ul><ul><li>true </li></ul><ul><li>because both objects content is same which is &quot;hello&quot;. </li></ul>
  37. 39. Optimization techniques when Concatenating Strings <ul><li>You can concatenate multiple strings using either </li></ul><ul><li> + operator </li></ul><ul><li> Or String.concat() </li></ul><ul><li> Or StringBuffer.append(). </li></ul><ul><li>Which is the best one interms of performance? </li></ul><ul><li>The choice depends on two scenarios: </li></ul><ul><li>􀀗 Compile time resolution VS. Run time resolution </li></ul><ul><li>􀀗 StringBuffer VS. String </li></ul><ul><li>In general, programmers think that StringBuffer.append() is better than + operator or String.concat() method. But this assumption is not true under certain conditions. </li></ul>
  38. 40. Compile time resolution VS. run time resolution… <ul><li>Interestingly the + operator is faster than StringBuffer.append() method. Let us see why? </li></ul><ul><li>Here the compiler does a good job of optimization. </li></ul><ul><li>Compiler simply concatenates at compile time as shown below. It does compile time resolution instead of runtime resolution </li></ul><ul><li>Before compilation: </li></ul><ul><li>String result = &quot;This is&quot;+&quot;testing the&quot;+&quot;difference&quot;+&quot;between&quot;+&quot;String&quot;+&quot;and&quot;+&quot;StringBuffer&quot;; </li></ul><ul><li>After compilation </li></ul><ul><li>String result = &quot;This is testing the difference between String and StringBuffer&quot;; </li></ul><ul><li>String object is resolved at compile time </li></ul><ul><li>StringBuffer object is resolved at run time. </li></ul><ul><li>Run time resolution takes place when the value of the string is not known in advance </li></ul><ul><li>Compile time resolution happens when the value of the string is known in advance. </li></ul>
  39. 41. Using StringBuffer instead of String <ul><li>It shows StringBuffer.append() is much more faster than String. Why? </li></ul><ul><li>The reason is both resolve at runtime but the + operator resolves in a different manner </li></ul>
  40. 42. Optimization by initializing StringBuffer <ul><li>You can set the initial capacity of StringBuffer using its constructor this improves performance significantly. </li></ul><ul><li>The constructor is StringBuffer(int length), length shows the number of characters the StringBuffer can hold. </li></ul><ul><li>When you create StringBuffer with default constructor StringBuffer() without setting initial length, then the StringBuffer is initialized with 16 characters. </li></ul><ul><li>When the StringBuffer reaches its maximum capacity, it will increase its size by twice the size plus 2 ( 2*old size +2). </li></ul><ul><li>Whenever it reaches its maximum capacity it has to create a new character array and recopy old and new characters. It is obviously expensive. </li></ul>
  41. 43. Performance improvement techniques in Serialization <ul><li>Overview of Serialization </li></ul><ul><li>Serialization is the process of writing complete state of java object into output stream, that stream can be file or byte array or stream associated with TCP/IP socket. </li></ul><ul><li>Deserialization is the process of reading back that serialized java object stream from input stream. </li></ul><ul><li>A java object is serializeable and deserializeable if that class follows the following rules </li></ul><ul><ul><li>The java class must implement java.io.Serializable interface or java.io.Externalizable interface or inherit that implementation from any one of it's super class implementation. </li></ul></ul><ul><ul><li>All instance variables of that class must implement Serializable interface or Externalizable interface or inherit from one of it's super class. </li></ul></ul><ul><ul><li>Serialization default mechanism </li></ul></ul><ul><ul><li>When you write or read an object to a file or network or other stream using serialization process. </li></ul></ul><ul><ul><li>It writes/reads the complete object state that means it writes </li></ul></ul><ul><ul><li>􀀗 the object </li></ul></ul><ul><ul><li>􀀗 it's instance variables </li></ul></ul><ul><ul><li>􀀗 super class instance variables </li></ul></ul><ul><ul><li>􀀗 except transient variables </li></ul></ul><ul><ul><li>􀀗 class (static) variables. </li></ul></ul>
  42. 44. Optimization with 'transient' <ul><li>In this class hierarchy, when I write CorporateEmployee object into file and read from that file </li></ul><ul><li>-- Initially Address is called </li></ul><ul><li>-- Second HomeAddress is called </li></ul><ul><li>-- Third Employee is called </li></ul><ul><li>-- Finally CorporateEmployee is called. </li></ul><ul><li>So Total object hierarchy will be written into file except transient and class (static) variables. </li></ul><ul><li>-- Variables that have access modifier 'transient' will not be read from or written into streams. </li></ul><ul><li>It gives facility to avoid writing unnecessary data into streams. </li></ul><ul><li>In other words, it boosts the performance by avoiding writing unnecessary data into streams. </li></ul>Serializable Employee String name HomeAddress ha CorporateEmployee String status HomeAddress String address Address String firstName String lastName
  43. 45. Performance improvement techniques in Exceptions <ul><li>Overview </li></ul><ul><li>Java provides an efficient way to handle unexpected conditions that can occur in the program. </li></ul><ul><li>The whole concept of exceptions/errors is handled by the java.lang.Throwable class. </li></ul><ul><li>It has two subclasses - Error and Exception. </li></ul><ul><li>We generally need not handle Errors, they are handled by JVM. </li></ul><ul><li>Example of Error is OutOfMemoryError. </li></ul>
  44. 46. Optimization techniques in Exceptions <ul><li>In a catch block avoid using the generic class Exception . For each try block use specific catch blocks based on what can go wrong in your code. </li></ul><ul><li>Do not use Exception handling for anything other than exception handling like to control the flow of your program. </li></ul><ul><li>Whenever you are using a throws clause always use the specific subclass of Exception like FileNotFoundException rather than using throws Exception. </li></ul><ul><li>Use exception handling generously-Very little overhead is imposed by using exception handling mechanism unless an exception occurs . But when an exception occurs it imposes an overhead in terms of execution time. </li></ul><ul><li>Always use the finally block to release the resources like a database connection, closing a file or socket connection etc. This prevents resource leaks even if an exception occurs. </li></ul><ul><li>When using method calls always handle the exceptions in the method where they occur, do not allow them to propagate to the calling method unless it is specifically required. It is efficient to handle them locally since allowing them to propagate to the calling method takes more execution time. </li></ul><ul><li>Do not use Exception handling in loops . It is better to place loops inside try/catch blocks than vice versa. </li></ul>
  45. 47. Performance improvement techniques in loops <ul><li>Overview </li></ul><ul><li>Loops provide efficient way for repeating a piece of code as many times as required. </li></ul><ul><li>Java has three types of loop control structures they are : </li></ul><ul><li> for loop </li></ul><ul><li>• is used when we know in advance how many iterations are required. </li></ul><ul><li> while loop </li></ul><ul><li>• is used when we do not know in advance the number of iterations required </li></ul><ul><li>• so each time before entering the loop the condition is checked </li></ul><ul><li>• if it is true then the loop is executed. </li></ul><ul><li> do-while loop. </li></ul><ul><li>• is always executed at least once and then the condition is checked at the end of the loop. </li></ul>
  46. 48. Optimization techinques in loops … <ul><li>Always use an int data type as the loop index variable whenever possible because it is efficient when compared to using byte or short data types. because when we use byte or short data type as the loop index variable they involve implicit type cast to int data type. </li></ul><ul><li>When using arrays it is always efficient to copy arrays using System.arraycopy() than using a loop. </li></ul><ul><li>Always avoid anything that can be done outside of the loop like method calls, assigning values to variables, or testing for conditions. </li></ul><ul><li>It is better to avoid accessing array elements in a loop. </li></ul><ul><li>􀀗 a). The better option would be to use a temporary variables inside the loop and modify the array values out of the loop. </li></ul><ul><li>b). It is fast to use a variable in a loop than accessing an array element. </li></ul><ul><li>Try to compare the terminating condition with zero if you use non-JIT or HotSpot virtual machine. JIT or HotSpot virtual machines are optimized for general loops so you do not have to bother about the terminating condition. </li></ul><ul><li>When using short circuit operators to test for loop termination tests </li></ul><ul><li>-- always put the expression that will most likely evaluate to false at extreme left. This saves all the following expressions from being tested in case there is an && operator </li></ul><ul><li>-- If there are only || operators then put the expression which is most likely to evaluate to true in the extreme left. </li></ul><ul><li>Avoid using try-catch inside the loops instead place the loops inside the try-catch for better performance </li></ul>
  47. 49. Java Base
  48. 50. Do you know the result? <ul><li>private static int finallyReturn(){ </li></ul><ul><li>int i = 1; </li></ul><ul><li>try { </li></ul><ul><li>return i*2; //2 </li></ul><ul><li>} finally { </li></ul><ul><li>i++; //2 </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  49. 51. Write a String Reverser <ul><li>Here is an interface: </li></ul><ul><li>public interface Reverser { </li></ul><ul><li>public String reverse(String str);    </li></ul><ul><li>} </li></ul><ul><li>Have a try to implement this function. </li></ul>
  50. 52. <ul><li>1. The best implementation in Java is to use the reverse method of the StringBuffer class in the JDK. </li></ul><ul><li>It’s fast, efficient and knows how to handle unicode surrogate pairs, something most other solutions ignore. </li></ul><ul><ul><ul><li>public class JdkReverser implements Reverser {    </li></ul></ul></ul><ul><ul><ul><li>        public String reverse(String str) {    </li></ul></ul></ul><ul><ul><ul><li>             if ((null == str) || (str.length() <= 1)) {    </li></ul></ul></ul><ul><ul><ul><li>                 return str;    </li></ul></ul></ul><ul><ul><ul><li>             }    </li></ul></ul></ul><ul><ul><ul><li>             return new StringBuffer(str).reverse().toString();    </li></ul></ul></ul><ul><ul><ul><li>         }    </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul>
  51. 53. <ul><li>2. use recursion </li></ul><ul><ul><ul><li>public String reverse(String str) {    </li></ul></ul></ul><ul><ul><ul><li>     if ((null == str) || (str.length()  <= 1)) {    </li></ul></ul></ul><ul><ul><ul><li>         return str;    </li></ul></ul></ul><ul><ul><ul><li>     }    </li></ul></ul></ul><ul><ul><ul><li>     return reverse(str.substring(1)) + str.charAt(0);    </li></ul></ul></ul><ul><ul><ul><li>}  </li></ul></ul></ul>
  52. 54. <ul><li>3. swapping a StringBuffer in place </li></ul><ul><ul><ul><li>public String reverse(String str) {    </li></ul></ul></ul><ul><ul><ul><li>     if ((null == str) || (str.length()  <= 1 )) {    </li></ul></ul></ul><ul><ul><ul><li>         return str;    </li></ul></ul></ul><ul><ul><ul><li>     }    </li></ul></ul></ul><ul><ul><ul><li>     StringBuffer result = new StringBuffer(str);    </li></ul></ul></ul><ul><ul><ul><li>     for (int i = 0; i < (str.length() / 2); i++) {    </li></ul></ul></ul><ul><ul><ul><li>         int swapIndex = str.length() - 1 - i;    </li></ul></ul></ul><ul><ul><ul><li>         char swap = result.charAt(swapIndex);    </li></ul></ul></ul><ul><ul><ul><li>         result.setCharAt(swapIndex, result.charAt(i));    </li></ul></ul></ul><ul><ul><ul><li>         result.setCharAt(i, swap);    </li></ul></ul></ul><ul><ul><ul><li>     }    </li></ul></ul></ul><ul><ul><ul><li>     return result.toString(); </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul>
  53. 55. <ul><li>4. swapping an array </li></ul><ul><ul><ul><ul><li>public String reverse(String str) {    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>     if ((null == str) || (str.length() <= 1)) {    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>         return str;    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>     }    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>     char[] chars = str.toCharArray();    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>     int right = chars.length - 1;    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>     for (int left = 0; left < right; left++) {    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>         char swap = chars[left];    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>         chars[left] = chars[right];    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>         chars[right--] = swap;    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>     }    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>     return new String(chars);    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>}   </li></ul></ul></ul></ul>
  54. 56. <ul><li>5. appending to a StringBuffer </li></ul><ul><ul><ul><ul><li>public String reverse(String str) {    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>         if ((null == str) || (str.length() <= 1)) {    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>             return str;    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>         }    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>         StringBuffer reverse = new StringBuffer(str.length());    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>         for (int i = str.length() - 1; i >= 0; i–) {    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>           reverse.append(str.charAt(i));    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>         }    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>         return reverse.toString();    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>     }    </li></ul></ul></ul></ul><ul><ul><ul><ul><li>} </li></ul></ul></ul></ul>
  55. 57. Hashtable <ul><li>/** </li></ul><ul><li>* The hash table data. </li></ul><ul><li>*/ </li></ul><ul><li>private transient Entry[] table; </li></ul><ul><li>/** </li></ul><ul><li>* The total number of entries in the hash table. </li></ul><ul><li>*/ </li></ul><ul><li>private transient int count; </li></ul><ul><li>/** </li></ul><ul><li>* The table is rehashed when its size exceeds this threshold. (The </li></ul><ul><li>* value of this field is (int)(capacity * loadFactor).) </li></ul><ul><li>* </li></ul><ul><li>* @serial </li></ul><ul><li>*/ </li></ul><ul><li>private int threshold ; </li></ul><ul><li>/** </li></ul><ul><li>* The load factor for the hashtable. </li></ul><ul><li>* </li></ul><ul><li>* @serial </li></ul><ul><li>*/ </li></ul><ul><li>private float loadFactor ; </li></ul><ul><li>/** </li></ul><ul><li>* The number of times this Hashtable has been structurally modified </li></ul><ul><li>* Structural modifications are those that change the number of entries in </li></ul><ul><li>* the Hashtable or otherwise modify its internal structure (e.g., </li></ul><ul><li>* rehash). This field is used to make iterators on Collection-views of </li></ul><ul><li>* the Hashtable fail-fast. (See ConcurrentModificationException). </li></ul><ul><li>*/ </li></ul><ul><li>private transient int modCount = 0; </li></ul>
  56. 58. <ul><li>private static class Entry <K,V> implements Map.Entry<K,V> { </li></ul><ul><li>int hash; </li></ul><ul><li>K key; </li></ul><ul><li>V value; </li></ul><ul><li>Entry<K,V> next; </li></ul><ul><li>protected Entry(int hash, K key, V value, Entry<K,V> next ) { </li></ul><ul><li> this.hash = hash; </li></ul><ul><li> this.key = key; </li></ul><ul><li> this.value = value; </li></ul><ul><li> this.next = next; </li></ul><ul><li>} </li></ul><ul><li>protected Object clone () { </li></ul><ul><li> return new Entry<K,V>(hash, key, value, (next==null ? null : (Entry<K,V>) next.clone())); </li></ul><ul><li>} </li></ul><ul><li>// Map.Entry Ops , methods implements from Map#Entry interface </li></ul><ul><li>public K getKey() { </li></ul><ul><li> return key; </li></ul><ul><li>} </li></ul><ul><li>public V getValue() { </li></ul><ul><li> return value; </li></ul><ul><li>} </li></ul><ul><li>public V setValue(V value) { </li></ul><ul><li> if (value == null) throw new NullPointerException(); </li></ul><ul><li> V oldValue = this.value; </li></ul><ul><li> this.value = value; </li></ul><ul><li> return oldValue; </li></ul><ul><li>} </li></ul><ul><li>public boolean equals (Object o) { </li></ul><ul><li> if (!(o instanceof Map.Entry)) return false; </li></ul><ul><li> Map.Entry e = (Map.Entry)o; </li></ul><ul><li> return (key==null ? e.getKey()==null : key.equals(e.getKey())) && (value==null ? e.getValue()==null : value.equals(e.getValue())); </li></ul><ul><li>} </li></ul><ul><li>public int hashCode () { </li></ul><ul><li> return hash ^ (value==null ? 0 : value.hashCode()); </li></ul><ul><li>} </li></ul><ul><li>public String toString () { </li></ul><ul><li> return key.toString()+&quot;=&quot;+value.toString(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  57. 59. <ul><li>Constructor </li></ul><ul><li>public Hashtable( int initialCapacity, float loadFactor) { </li></ul><ul><li>if (initialCapacity < 0) </li></ul><ul><li> throw new IllegalArgumentException(&quot;Illegal Capacity: &quot;+initialCapacity); </li></ul><ul><li>if (loadFactor <= 0 || Float.isNaN(loadFactor)) </li></ul><ul><li> throw new IllegalArgumentException(&quot;Illegal Load: &quot;+loadFactor); </li></ul><ul><li>if (initialCapacity==0) </li></ul><ul><li>initialCapacity = 1; </li></ul><ul><li>this.loadFactor = loadFactor; </li></ul><ul><li>table = new Entry[initialCapacity]; </li></ul><ul><li>threshold = (int)(initialCapacity * loadFactor); </li></ul><ul><li>} </li></ul><ul><li>public Hashtable( int initialCapacity) { </li></ul><ul><li>this ( initialCapacity , 0.75f); </li></ul><ul><li>} </li></ul><ul><li>public Hashtable() { </li></ul><ul><li>this (11, 0.75f); </li></ul><ul><li>} </li></ul>
  58. 60. <ul><li>rehash() </li></ul><ul><li>/** </li></ul><ul><li>* Increases the capacity of and internally reorganizes this hashtable, </li></ul><ul><li>* in order to accommodate and access its entries more efficiently. </li></ul><ul><li>* This method is called automatically when the number of keys in the hashtable </li></ul><ul><li>* exceeds this hashtable's capacity and load factor. </li></ul><ul><li>*/ </li></ul><ul><li>protected void rehash() { </li></ul><ul><li>int oldCapacity = table.length; </li></ul><ul><li>Entry[] oldMap = table; </li></ul><ul><li>int newCapacity = oldCapacity * 2 + 1; </li></ul><ul><li>Entry[] newMap = new Entry[newCapacity]; </li></ul><ul><li>modCount++; </li></ul><ul><li>threshold = (int)(newCapacity * loadFactor); </li></ul><ul><li>table = newMap; </li></ul><ul><li>for (int i = oldCapacity ; i-- > 0 ;) { </li></ul><ul><li> for (Entry<K,V> old = oldMap[i] ; old != null ; ) { </li></ul><ul><li>Entry<K,V> e = old; </li></ul><ul><li>old = old.next; </li></ul><ul><li>int index = (e.hash & 0x7FFFFFFF) % newCapacity; </li></ul><ul><li>e.next = newMap[index]; </li></ul><ul><li>newMap[index] = e; </li></ul><ul><li> } </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  59. 61. <ul><li>public synchronized V pu t(K key, V value) { </li></ul><ul><li>// Make sure the value is not null </li></ul><ul><li>if (value == null) { </li></ul><ul><li> throw new NullPointerException(); </li></ul><ul><li>} </li></ul><ul><li>// Makes sure the key is not already in the hashtable . </li></ul><ul><li>Entry tab[] = table; </li></ul><ul><li>int hash = key.hashCode(); </li></ul><ul><li>int index = (hash & 0x7FFFFFFF) % tab.length; </li></ul><ul><li>for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) { </li></ul><ul><li> if ((e.hash == hash) && e.key.equals(key)) { </li></ul><ul><li>V old = e.value; </li></ul><ul><li>e.value = value; </li></ul><ul><li>return old; </li></ul><ul><li> } </li></ul><ul><li>} </li></ul><ul><li>modCount++; </li></ul><ul><li>if (count >= threshold) { </li></ul><ul><li> // Rehash the table if the threshold is exceeded </li></ul><ul><li> rehash(); </li></ul><ul><li>tab = table; </li></ul><ul><li>index = (hash & 0x7FFFFFFF) % tab.length; </li></ul><ul><li>} </li></ul><ul><li>// Creates the new entry. </li></ul><ul><li>Entry<K,V> e = tab[index]; </li></ul><ul><li>tab[index] = new Entry<K,V>(hash, key, value, e); </li></ul><ul><li>count++; </li></ul><ul><li>return null; </li></ul><ul><li>} </li></ul>public synchronized V remove (Object key) { Entry tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { modCount++; if (prev != null) { prev.next = e.next; } else { tab[index] = e.next; } count--; V oldValue = e.value; e.value = null; return oldValue; } } return null; }
  60. 62. <ul><li>/** </li></ul><ul><li>* Creates a shallow copy of this hashtable. All the structure of the </li></ul><ul><li>* hashtable itself is copied, but the keys and values are not cloned. </li></ul><ul><li>* This is a relatively expensive operation. </li></ul><ul><li>* </li></ul><ul><li>* @return a clone of the hashtable. </li></ul><ul><li>*/ </li></ul><ul><li>public synchronized Object clone () { </li></ul><ul><li>try { </li></ul><ul><li> Hashtable<K,V> t = (Hashtable<K,V>) super.clone(); </li></ul><ul><li> t.table = new Entry[table.length]; </li></ul><ul><li> for (int i = table.length ; i-- > 0 ; ) { </li></ul><ul><li>t.table[i] = (table[i] != null) </li></ul><ul><li> ? (Entry<K,V>) table[i].clone() : null; </li></ul><ul><li> } </li></ul><ul><li> t.keySet = null; </li></ul><ul><li> t.entrySet = null; </li></ul><ul><li>t.values = null; </li></ul><ul><li> t.modCount = 0; </li></ul><ul><li> return t; </li></ul><ul><li>} catch (CloneNotSupportedException e) { </li></ul><ul><li> // this shouldn't happen, since we are Cloneable </li></ul><ul><li> throw new InternalError(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>/** * Returns a string representation of this <tt>Hashtable</tt> object * in the form of a set of entries, enclosed in braces and separated * by the ASCII characters &quot;<tt>,&nbsp;</tt>&quot; (comma and space). Each * entry is rendered as the key, an equals sign <tt>=</tt>, and the * associated element, where the <tt>toString</tt> method is used to * convert the key and element to strings. <p>Overrides to * <tt>toString</tt> method of <tt>Object</tt>. * * @return a string representation of this hashtable. */ public synchronized String toString () { int max = size() - 1; StringBuffer buf = new StringBuffer(); Iterator<Map.Entry<K,V>> it = entrySet().iterator(); buf.append(&quot;{&quot;); for (int i = 0; i <= max; i++) { Map.Entry<K,V> e = it.next(); K key = e.getKey(); V value = e.getValue(); buf.append((key == this ? &quot;(this Map)&quot; : (&quot;&quot;+key)) + &quot;=&quot; + (value == this ? &quot;(this Map)&quot; : (&quot;&quot;+value))); if (i < max) buf.append(&quot;, &quot;); } buf.append(&quot;}&quot;); return buf.toString(); }
  61. 63. <ul><li>private synchronized void writeObject (java.io.ObjectOutputStream s)throws IOException { </li></ul><ul><li>// Write out the length, threshold, loadfactor </li></ul><ul><li>s.defaultWriteObject(); </li></ul><ul><li>// Write out length, count of elements and then the key/value objects </li></ul><ul><li>s.writeInt(table.length); </li></ul><ul><li>s.writeInt(count); </li></ul><ul><li>for (int index = table.length-1; index >= 0; index--) { </li></ul><ul><li> Entry entry = table[index]; </li></ul><ul><li> while (entry != null) { </li></ul><ul><li>s.writeObject(entry.key); </li></ul><ul><li>s.writeObject(entry.value); </li></ul><ul><li>entry = entry.next; </li></ul><ul><li> } </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>private void readObject (java.io.ObjectInputStream s)throws IOException, ClassNotFoundException { // Read in the length, threshold, and loadfactor s.defaultReadObject(); // Read the original length of the array and number of elements int origlength = s.readInt(); int elements = s.readInt(); // Compute new size with a bit of room 5% to grow but // no larger than the original size. Make the length // odd if it's large enough, this helps distribute the entries. // Guard against the length ending up zero, that's not valid. int length = (int)(elements * loadFactor) + (elements / 20) + 3; if (length > elements && (length & 1) == 0) length--; if (origlength > 0 && length > origlength) length = origlength; table = new Entry[length]; count = 0; // Read the number of elements and then all the key/value objects for (; elements > 0; elements--) { K key = (K)s.readObject(); V value = (V)s.readObject(); // synch could be eliminated for performance reconstitutionPut(key, value); } }
  62. 64. <ul><li>/** </li></ul><ul><li>* A hashtable enumerator class. This class implements both the </li></ul><ul><li>* Enumeration and Iterator interfaces, but individual instances </li></ul><ul><li>* can be created with the Iterator methods disabled. This is necessary </li></ul><ul><li>* to avoid unintentionally increasing the capabilities granted a user </li></ul><ul><li>* by passing an Enumeration. </li></ul><ul><li>*/ </li></ul><ul><li>private class Enumerator<T> implements Enumeration<T>, Iterator<T> { </li></ul><ul><li>Entry[] table = Hashtable.this.table; </li></ul><ul><li>int index = table.length; </li></ul><ul><li>Entry<K,V> entry = null; </li></ul><ul><li>Entry<K,V> lastReturned = null; </li></ul><ul><li>int type; </li></ul><ul><li>/** </li></ul><ul><li> * Indicates whether this Enumerator is serving as an Iterator </li></ul><ul><li> * or an Enumeration. (true -> Iterator). </li></ul><ul><li> */ </li></ul><ul><li>boolean iterator; </li></ul><ul><li>/** </li></ul><ul><li> * The modCount value that the iterator believes that the backing </li></ul><ul><li> * List should have. If this expectation is violated, the iterator </li></ul><ul><li> * has detected concurrent modification. </li></ul><ul><li> */ </li></ul><ul><li>protected int expectedModCount = modCount; </li></ul><ul><li>Enumerator(int type, boolean iterator) { </li></ul><ul><li> this.type = type; </li></ul><ul><li> this.iterator = iterator; </li></ul><ul><li>} </li></ul><ul><li>public boolean hasMoreElements() { </li></ul><ul><li> Entry<K,V> e = entry; </li></ul><ul><li> int i = index; </li></ul><ul><li> Entry[] t = table; </li></ul><ul><li> /* Use locals for faster loop iteration */ </li></ul><ul><li> while (e == null && i > 0) { </li></ul><ul><li>e = t[--i]; </li></ul><ul><li> } </li></ul><ul><li> entry = e; </li></ul><ul><li> index = i; </li></ul><ul><li> return e != null; </li></ul><ul><li>} </li></ul> public T nextElement() { Entry<K,V> et = entry; int i = index; Entry[] t = table; /* Use locals for faster loop iteration */ while (et == null && i > 0) { et = t[--i]; } entry = et; index = i; if (et != null) { Entry<K,V> e = lastReturned = entry; entry = e.next; return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e); } throw new NoSuchElementException(&quot;Hashtable Enumerator&quot;); } // Iterator methods public boolean hasNext() { return hasMoreElements(); } public T next() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); return nextElement(); } public void remove () { if (!iterator) throw new UnsupportedOperationException(); if (lastReturned == null) throw new IllegalStateException(&quot;Hashtable Enumerator&quot;); if (modCount != expectedModCount) throw new ConcurrentModificationException(); synchronized(Hashtable.this) { Entry[] tab = Hashtable.this.table; int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length; for (Entry<K,V> e = tab[index], prev = null; e != null; prev = e, e = e.next) { if (e == lastReturned) { modCount++; expectedModCount++; if (prev == null) tab[index] = e.next; else prev.next = e.next; count--; lastReturned = null; return; } } throw new ConcurrentModificationException(); } } }
  63. 65. HashMap <ul><li>static final int DEFAULT_INITIAL_CAPACITY = 16; </li></ul><ul><li>static final int MAXIMUM_CAPACITY = 1 << 30; </li></ul><ul><li>static final float DEFAULT_LOAD_FACTOR = 0.75f; </li></ul><ul><li>/** </li></ul><ul><li>* Returns a hash value for the specified object. In addition to </li></ul><ul><li>* the object's own hashCode, this method applies a &quot;supplemental </li></ul><ul><li>* hash function,&quot; which defends against poor quality hash functions. </li></ul><ul><li>* This is critical because HashMap uses power-of two length </li></ul><ul><li>* hash tables.<p> </li></ul><ul><li>* </li></ul><ul><li>* The shift distances in this function were chosen as the result </li></ul><ul><li>* of an automated search over the entire four-dimensional search space. </li></ul><ul><li>*/ </li></ul><ul><li>static int hash (Object x) { </li></ul><ul><li>int h = x.hashCode(); </li></ul><ul><li>h += ~(h << 9); </li></ul><ul><li>h ^= (h >>> 14); </li></ul><ul><li>h += (h << 4); </li></ul><ul><li>h ^= (h >>> 10); </li></ul><ul><li>return h; </li></ul><ul><li>} </li></ul>/** * Rehashes the contents of this map into a new array with a * larger capacity. This method is called automatically when the * number of keys in this map reaches its threshold. * * If current capacity is MAXIMUM_CAPACITY, this method does not * resize the map, but sets threshold to Integer.MAX_VALUE. * This has the effect of preventing future calls. * * @param newCapacity the new capacity, MUST be a power of two; * must be greater than current capacity unless current * capacity is MAXIMUM_CAPACITY (in which case value * is irrelevant). */ void resize ( int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY ) { threshold = Integer. MAX_VALUE ; return ; } Entry[] newTable = new Entry[newCapacity]; transfer(newTable); table = newTable; threshold = ( int )(newCapacity * loadFactor); }
  64. 66. The Singleton Pattern <ul><li>A creational pattern </li></ul><ul><li>With the Singleton design pattern you can: </li></ul><ul><li>-- Ensure that only one instance of a class is created </li></ul><ul><li>-- Provide a global point of access to the object </li></ul><ul><li>-- Allow multiple instances in the future without affecting a singleton class's clients </li></ul><ul><li>class diagram </li></ul><ul><li>The simplest design patterns? </li></ul><ul><li>public class ClassicSingleton { </li></ul><ul><li>private static ClassicSingleton instance = null; </li></ul><ul><li>protected ClassicSingleton() { </li></ul><ul><li>// Exists only to defeat instantiation. </li></ul><ul><li>} </li></ul><ul><li>public static ClassicSingleton getInstance() { </li></ul><ul><li>if(instance == null) { </li></ul><ul><li>instance = new ClassicSingleton(); </li></ul><ul><li>} </li></ul><ul><li>return instance; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>What is the problem?
  65. 67. <ul><li>1. ClassicSingleton employs a technique known as lazy instantiation to create the singleton; as a result, the singleton instance is not created until the getInstance() method is called for the first time. </li></ul><ul><li>2. protected constructor , solutions: </li></ul><ul><li>a. use private instead  can not be subclassed  then it’s a good idea to declare your singleton class final; </li></ul><ul><li>b. put your singleton class in an explicit package , so classes in other packages cannot instantiate singleton instances. </li></ul><ul><li>3. It's possible to have multiple singleton instances if classes loaded by different classloaders access a singleton. For example, some servlet containers use distinct classloaders for each servlet, so if two servlets access a singleton, they will each have their own instance. </li></ul><ul><li>4. If ClassicSingleton implements the java.io.Serializable interface, the class's instances can be serialized and deserialized. However, if you serialize a singleton object and subsequently deserialize that object more than once, you will have multiple singleton instances. </li></ul><ul><li>5. The ClassicSingleton is not thread-safe . </li></ul>
  66. 68. <ul><li>Multithreading considerations </li></ul><ul><li>public synchronized static Singleton getInstance() { </li></ul><ul><li> if(singleton == null) { </li></ul><ul><li> singleton = new Singleton(); </li></ul><ul><li> } </li></ul><ul><li> return singleton; </li></ul><ul><li>} </li></ul><ul><li>However , you may realize that the getInstance() method only needs to be synchronized the first time it is called. Performance enhancement: </li></ul><ul><li>public static Singleton getInstance() { </li></ul><ul><li> if(singleton == null) { </li></ul><ul><li> synchronized (Singleton.class){ </li></ul><ul><li>singleton = new Singleton(); </li></ul><ul><li>} </li></ul><ul><li> } </li></ul><ul><li> return singleton; </li></ul><ul><li>} </li></ul><ul><li>Instead of synchronizing the entire method, the preceding code fragment only synchronizes the critical code. </li></ul><ul><li>However , still not thread-safe: Another thread can enter the if block before the first thread starts to instantiate the class. </li></ul>
  67. 69. <ul><li>Double-checked locking </li></ul><ul><li>public static Singleton getInstance() { </li></ul><ul><li> if(singleton == null) { </li></ul><ul><li> synchronized (Singleton.class){ </li></ul><ul><li> if(singleton == null){ </li></ul><ul><li>singleton = new Singleton(); </li></ul><ul><li> } </li></ul><ul><li>} </li></ul><ul><li> } </li></ul><ul><li> return singleton; </li></ul><ul><li>} </li></ul><ul><li>Unfortunately , it is still not guaranteed to work because the compiler is free to assign a value to the singleton member variable before the singleton's constructor is called. So , we come back, you must synchronize the entire getInstance() method. </li></ul><ul><li>However , another alternative is simple, fast, and thread-safe. </li></ul><ul><li>public class Singleton { </li></ul><ul><li> public final static Singleton INSTANCE = new Singleton(); </li></ul><ul><li> private Singleton() { </li></ul><ul><li> // Exists only to defeat instantiation. </li></ul><ul><li> } </li></ul><ul><li>} </li></ul><ul><li>Singleton singleton = Singleton.INSTANCE; </li></ul><ul><li>singleton.dothis(); </li></ul><ul><li>Problem is: if you use that implementation, you can't change your mind and allow multiple singleton instances later on. </li></ul>
  68. 70. <ul><li>Use a registry </li></ul><ul><li>Use a singleton registry to: </li></ul><ul><li>Specify singleton classes at runtime </li></ul><ul><li>Prevent singleton subclasses from allowing multiple instances </li></ul><ul><li>import java.util.HashMap; </li></ul><ul><li>public class Singleton { </li></ul><ul><li>private static HashMap map = new HashMap(); </li></ul><ul><li>protected Singleton() { </li></ul><ul><li>// Exists only to thwart instantiation </li></ul><ul><li>} </li></ul><ul><li>public static synchronized Singleton getInstance(String classname) { </li></ul><ul><li>if(classname == null){ </li></ul><ul><li> throw new IllegalArgumentException(&quot;Illegal classname&quot;); </li></ul><ul><li>} </li></ul><ul><li>Singleton singleton = (Singleton)map.get(classname); </li></ul><ul><li>if(singleton != null) { </li></ul><ul><li>return singleton; </li></ul><ul><li>} </li></ul><ul><li>if(classname.equals(&quot;SingeltonSubclass_One&quot;)) </li></ul><ul><li>singleton = new SingletonSubclass_One(); </li></ul><ul><li>else if(classname.equals(&quot;SingeltonSubclass_Two&quot;)) </li></ul><ul><li>singleton = new SingletonSubclass_Two(); </li></ul><ul><li>map.put(classname, singleton); </li></ul><ul><li>return singleton; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>Use reflection import java.util.HashMap; public class Singleton { private static HashMap map = new HashMap(); protected Singleton() { // Exists only to thwart instantiation } public static synchronized Singleton getInstance(String classname) { if(classname == null){ throw new IllegalArgumentException(&quot;Illegal classname&quot;); } Singleton singleton = (Singleton)map.get(classname); if(singleton != null) { return singleton; } try { singleton = (Singleton)Class.forName(classname).newInstance(); } catch(ClassNotFoundException cnf) { …… } catch(InstantiationException ie) { …… } catch(IllegalAccessException ia) { …… } map.put(classname, singleton); return singleton; } }
  69. 71. <ul><li>Encapsulate the registry </li></ul><ul><li>One more thing concerning singleton registries: they should be encapsulated in their own class for maximum reuse. </li></ul><ul><li>import java.util.HashMap; </li></ul><ul><li>public class SingletonRegistry { </li></ul><ul><li>public static SingletonRegistry REGISTRY = new SingletonRegistry(); </li></ul><ul><li>private static HashMap map = new HashMap(); </li></ul><ul><li>protected SingletonRegistry() { </li></ul><ul><li>// Exists to defeat instantiation </li></ul><ul><li>} </li></ul><ul><li>public static synchronized Object getInstance(String classname) { </li></ul><ul><li>if(classname == null) { </li></ul><ul><li>throw new IllegalArgumentException(&quot;Illegal classname&quot;); </li></ul><ul><li>} </li></ul><ul><li>Object singleton = map.get(classname); </li></ul><ul><li>if(singleton != null) { </li></ul><ul><li>return singleton; </li></ul><ul><li>} </li></ul><ul><li>try { </li></ul><ul><li>singleton = Class.forName(classname).newInstance(); </li></ul><ul><li>} catch(ClassNotFoundException cnf) { </li></ul><ul><li>...... </li></ul><ul><li>} catch(InstantiationException ie) { </li></ul><ul><li>...... </li></ul><ul><li>} catch(IllegalAccessException ia) { </li></ul><ul><li>...... </li></ul><ul><li>} </li></ul><ul><li>map.put(classname, singleton); </li></ul><ul><li>return singleton; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>public class Singleton { </li></ul><ul><li>protected Singleton() { </li></ul><ul><li>// Exists only to thwart instantiation. </li></ul><ul><li>} </li></ul><ul><li>public static Singleton getInstance() { </li></ul><ul><li>return (Singleton) SingletonRegistry.REGISTRY.getInstance(classname); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  70. 72. <ul><li>ClassLoaders </li></ul><ul><li>Because multiple classloaders are commonly used in many situations—including servlet containers. If you want to make sure the same classloader loads your singletons, you must specify the classloader yourself; for example: </li></ul><ul><ul><li>private static Class getClass(String classname) throws ClassNotFoundException{ </li></ul></ul><ul><ul><li>ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); </li></ul></ul><ul><ul><li>if(classLoader == null){ </li></ul></ul><ul><ul><li>classLoader = Singleton.class.getClassLoader(); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>return (classLoader.loadClass(classname)); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>Serialization </li></ul><ul><li>If you serialize a singleton and then deserialize it twice, you will have two instances of your singleton, unless you implement the readResolve() method, like this: </li></ul><ul><ul><li>public class Singleton implements java.io.Serializable { </li></ul></ul><ul><ul><li>public static Singleton INSTANCE = new Singleton(); </li></ul></ul><ul><ul><li>protected Singleton() { </li></ul></ul><ul><ul><li>// Exists only to thwart instantiation. </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>private Object readResolve() { </li></ul></ul><ul><ul><li>return INSTANCE; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul>
  71. 73. <ul><li>Singleton vs. static </li></ul><ul><li>public class Static{ </li></ul><ul><ul><li>public static void doVeryUsefulThing(){ </li></ul></ul><ul><ul><li>//some operations.. </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>} </li></ul><ul><li>Question is : What’s the difference? </li></ul>
  72. 74. <ul><li>Singleton vs. static </li></ul><ul><li>A singleton class has all the disadvantages of statics. </li></ul><ul><li>With a Singleton, if you choose to no longer have a Singleton, it is easy to change. </li></ul><ul><li>One of the strong anti-patterns in Java is the constant abuse of statics to hold state that really should be dynamic. Avoiding overuse of statics will generally give you a more flexible design. </li></ul><ul><li>Some good uses of statics: </li></ul><ul><ul><li>-- obtaining constants </li></ul></ul><ul><ul><li>-- factory methods </li></ul></ul><ul><ul><li>-- stateless methods (though this can often live better in their own class) </li></ul></ul><ul><li>In a simple Java application, you will normally have only one instance of Class per class you load. Because of this, a static member variable is usually unique. </li></ul><ul><li>However, in reality, you can have one instance of a Class per classloader . A more complex application, particularly J2EE applications, can easily have multiple classloaders. In this scenario, you end up have multiple instances of static variables. </li></ul>
  73. 75. <ul><li>synchronized instance methods </li></ul><ul><li>synchronized static methods </li></ul><ul><li>synchronized block </li></ul><ul><li>volatile </li></ul>
  74. 76. <ul><li>Threads - Thread Synchronization </li></ul><ul><li>every instance of class Object and its subclass's has a lock </li></ul><ul><li>primitive data type fields can only be locked via their enclosing class </li></ul><ul><li>fields cannot be marked as synchronized however they can be declared volatile which orders the way they can be used or you can write synchronized accessor methods </li></ul><ul><li>array objects can be synchronized BUT their elements cannot, nor can their elements be declared volatile </li></ul><ul><li>Class instances are Objects and can be synchronized via static synchronized methods </li></ul>
  75. 77. <ul><li>Synchronized blocks </li></ul><ul><li>allow you to execute synchronized code that locks an object without requiring you to invoke a synchronized method </li></ul><ul><li>synchronized( expr ) { </li></ul><ul><li> // 'expr' must evaluate to an Object </li></ul><ul><li>} </li></ul><ul><li>Synchronized methods </li></ul><ul><li>declaring a method as synchronized ie synchronized void f() is equivalent to </li></ul><ul><li>void f() { </li></ul><ul><li>synchronized(this) { </li></ul><ul><li>// body of method </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>the synchronized keyword is NOT considered part of a method's signature. IT IS NOT AUTOMATICALLY INHERITED when subclasses override superclass methods </li></ul><ul><li>methods in Interfaces CANNOT be declared synchronized </li></ul><ul><li>constructors CANNOT be declared synchronized however they can contain synchronized blocks </li></ul><ul><li>synchronized methods in subclasses use the same locks as their superclasses </li></ul><ul><li>synchronization of an Inner Class is independent on it's outer class </li></ul><ul><li>a non-static inner class method can lock it's containing class by using a synchronized block </li></ul><ul><li>synchronized(OuterClass.this) { </li></ul><ul><li>// body </li></ul><ul><li>} </li></ul>
  76. 78. <ul><li>Locking </li></ul><ul><li>locking follows a built-in acquire-release protocol controlled by the synchronized keyword </li></ul><ul><li>a lock is acquired on entry to a synchronized method or block and released on exit, even if the exit is the result of an exception </li></ul><ul><li>you cannot forget to release a lock </li></ul><ul><li>locks operate on a per thread basis, not on a per-invocation basis </li></ul><ul><li>Java uses re-entrant locks ie a thread cannot lock on itself </li></ul><ul><li>class Reentrant { </li></ul><ul><li>public synchronized void a() { </li></ul><ul><li>b(); </li></ul><ul><li>System.out.println(&quot;here I am, in a()&quot;); </li></ul><ul><li>} </li></ul><ul><li>public synchronized void b() { </li></ul><ul><li>System.out.println(&quot;here I am, in b()&quot;); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>in the above code, the synchronized method a(), when executed, obtains a lock on it's own object. It then calls synchronized method b() which also needs to acquire a lock on it's own object </li></ul><ul><li>if Java did not allow a thread to reacquire it's own lock method b() would be unable to proceed until method a() completed and released the lock; and method a() would be unable to complete until method b() completed. Result: deadlock </li></ul><ul><li>as Java does allow reentrant locks, the code compiles and runs without a problem </li></ul><ul><li>the locking protocol is only followed for synchronized methods, it DOES NOT prevent unsynchronized methods from accessing the object </li></ul><ul><li>once a thread releases a lock, another thread may acquire it BUT there is no guarantee as to WHICH thread will acquire the lock next </li></ul>
  77. 79. <ul><li>Class fields and methods </li></ul><ul><li>locking an object does not automatically protect access to static fields </li></ul><ul><li>protecting static fields requires a synchronized static block or method </li></ul><ul><li>static synchronized statements obtain a lock on the Class vs an instance of the class </li></ul><ul><li>a synchronized instance method can obtain a lock on the class </li></ul><ul><li>synchronized(ClassName.class){ </li></ul><ul><li>// body </li></ul><ul><li>} </li></ul><ul><li>the static lock on a class is not related to any other class including it's superclasses </li></ul><ul><li>a lock on a static method has no effect on any instances of that class </li></ul><ul><li>you cannot effectively protect static fields in a superclass by adding a new static synchronized method in a subclass; an explicit block synchronization is the preferred way </li></ul><ul><li>nor should you use synchronized(getClass()); this locks the actual Class which might be different from the class in which the static fields are declared </li></ul>
  78. 80. ThreadLocal <ul><li>A ThreadLocal is a variable that has a per-thread value. Different Threads may reference the same ThreadLocal object, but the values they observe will not be ==. This provides Thread local storage. </li></ul><ul><li>For example, in the class below, the private static ThreadLocal instance (serialNum) maintains a &quot;serial number&quot; for each thread that invokes the class's static SerialNum.get() method, which returns the current thread's serial number. (A thread's serial number is assigned the first time it invokes SerialNum.get(), and remains unchanged on subsequent calls.) </li></ul><ul><li>public class SerialNum { </li></ul><ul><li>// The next serial number to be assigned </li></ul><ul><li>private static int nextSerialNum = 0; </li></ul><ul><li>private static ThreadLocal serialNum = new ThreadLocal() { </li></ul><ul><li>protected synchronized Object initialValue() { </li></ul><ul><li>return new Integer(nextSerialNum++); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>public static int get() { </li></ul><ul><li>return ((Integer) (serialNum.get())).intValue(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the ThreadLocal instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist). </li></ul>
  79. 81. NIO <ul><li>The APIs of NIO were designed to provide access to the low-level I/O operations of modern operating systems. </li></ul><ul><li>http://developer.java.sun.com/developer/technicalArticles/releases/nio/ The java.nio packages </li></ul><ul><li>Tips: </li></ul><ul><li>Direct buffers have a higher creation cost than non-direct buffers because they use native system operations rather than JVM operations. </li></ul><ul><li>Direct buffers optimize access operations by using the system's native I/O operations. </li></ul><ul><li>Reduce threads by multiplexing I/O using selectors: The new I/O capabilities, allow you to create a Web server that does not require one thread per connection. </li></ul>
  80. 82. <ul><li>http://www.javaworld.com/javaworld/jw-09-2001/jw-0907-merlin.html Using nonblocking I/O and memory-mapped buffers in SDK 1.4. </li></ul><ul><li>Before SDK 1.4, servers had a number of performance problems: i/o could easily be blocked; garbage was easily generated when reading i/o; many threads are needed to scale the server. </li></ul><ul><li>Many threads each blocked on i/o is an inefficient architecture in comparison to one thread blocked on many i/o calls ( multiplexed i/o ). </li></ul><ul><li>Truly high-performance applications must obsess about garbage collection. The more garbage generated, the lower the application throughput . </li></ul><ul><li>A Buffer (java.nio.*Buffer) is a reusable portion of memory. A MappedByteBuffer can map a portion of a file directly into memory . </li></ul><ul><li>Direct Buffer objects can be read/written directly from Channels, but nondirect Buffer objects have a data copy performed for read/writes to i/o (and so are slower and may generate garbage). Convert nondirect Buffers to direct Buffers if they will be used more than once . </li></ul><ul><li>Scatter/gather operations allow i/o to operate to and from several Buffers in one operation , for increased efficiency. Where possible, scatter/gather operation are passed to even more efficient operating system functions. </li></ul><ul><li>Channels can be configured to operate blocking or non-blocking i/o . </li></ul><ul><li>Using a MappedByteBuffer is more efficient than using BufferedInputStreams. The operating system can page into memory more efficiently than BufferedInputStream can do a block read. </li></ul><ul><li>Use Selectors to multiplex i/o and avoid having to block multiple threads waiting on i/o. </li></ul>
  81. 83. <ul><li>Asynchronous </li></ul><ul><li>Transaction </li></ul><ul><li>cluster </li></ul>

×