What is volatile in java ?

Voltile in Java with explanation and example

If you are working with the multi-threaded programming, the volatile keyword will be more useful. When multiple threads using the same variable, each thread will have its own copy of the local cache for that variable. So, when it's updating the value, it is actually updated in the local cache not in the main variable memory. The other thread which is using the same variable doesn't know anything about the values changed by the another thread. To avoid this problem, if you declare a variable as volatile, then it will not be stored in the local cache. Whenever thread are updating the values, it is updated to the main memory. So, other threads can access the updated value.


public class VolatileExample {

public static void main(String args[]) {

new ExampleThread("Thread 1 ").start();

new ExampleThread("Thread 2 ").start();

}

}

class ExampleThread extends Thread {

private volatile int testValue;

public ExampleThread(String str){

super(str);

}

public void run() {

for (int i = 0; i <>

try {

System.out.println(getName() + " : "+i);

if (getName().equals("Thread 1 "))

{

testValue = 10;

}

if (getName().equals("Thread 2 "))

{

System.out.println( "Test Value : " + testValue);

}

Thread.sleep(1000);

} catch (InterruptedException exception) {

exception.printStackTrace();

}

}

}

}




Event Inheritance Model in Java Swing

The 1.0 Event Model (Event Inheritance Model)

The model for event processing in version 1.0 of the AWT is based on inheritance. In order for a program to catch and process GUI events, it must subclass GUI components and override either action() or handleEvent() methods. Returning "true" from one of these methods consumes the event so it is not processed further; otherwise the event is propagated sequentially up the GUI hierarchy until either it is consumed or the root of the hierarchy is reached. The result of this model is that programs have essentially two choices for structuring their event-handling code:
  1. Each individual component can be subclassed to specifically handle its target events. The result of this is a plethora of classes.
  2. All events for an entire hierarchy (or subset thereof) can be handled by a particular container; the result is that the container's overridden action() or handleEvent() method must contain a complex conditional statement in order to process the events.

Issues with the 1.0 Event Model

While the above model works fine for small applets with simple interfaces, it does not scale well for larger java programs for the following reasons:

  • The requirement to subclass a component in order make any real use of its functionality is cumbersome to developers; subclassing should be reserved for circumstances where components are being extended in some functional or visual way.
  • The inheritance model does not lend itself well to maintaining a clean separation between the application model and the GUI because application code must be integrated directly into the subclassed components at some level.
  • Since ALL event types are filtered through the same methods, the logic to process the different event types (and possibly the event targets in approach #2) is complex and error-prone. It is not uncommon for programs to have perplexing bugs that are the result of returning an incorrect result (true or false) from the handleEvent() method. This becomes an even greater problem as new event types are added to the AWT; if the logic of existing handleEvent() methods isn't set up to deal properly with unknown types, programs could potentially break in very unpredictable ways.
  • There is no filtering of events. Events are always delivered to components regardless of whether the components actually handle them or not. This is a general performance problem, particularly with high-frequency type events such as mouse moves.
  • For many components, the action() method passes a String parameter which is equivalent to either the label of the component (Button, MenuItem) or the item selected (List, Choice). For programs which use approach #2, this often leads to poor coding and unwieldy string-compare logic that doesn't localize well.

Continue statement in Java with sample


Continue: The continue statement is used in many programming languages such as C, C++, java etc. Sometimes we do not need to execute some statements under the loop then we use the continue statement that stops the normal flow of the control and control returns to the loop without executing the statements written after the continue statement. There is the difference between break and continue statement that the break statement exit control from the loop but continue statement keeps continuity in loop without executing the statement written after the continue statement according to the conditions.


In this program we will see that how the continue statement is used to stop the execution after that.

- no title specified

- no title specified- no title specified- no title specified- no title specified

public class Continue {

public static void main(String[] args) {

Thread t = new Thread();

try {

for (int i = 1; i < 10; i++) {

if (i == 5) {

continue;

// break now and continue the loop.

}

t.sleep(1000);

System.out.println("Value of i : " + i);

}

} catch (InterruptedException e) {

}

}

}







Difference between DataSource and DriverManager

Difference between DataSource, Database and DriverManager

There are two sources of database connections - either a DataSource or a DriverManager.

If available, JNDI and the DataSource interface should be used to get a Connection instead of DriverManager. The JNDI style is typical when using an application server or a web container. (For example, the popular Tomcat product includes JNDI services and connection pools.)

Always remember that database connections need to be properly released!

Options for specifying the connection parameters include :

  • server configuration settings (likely the most common style)
  • direct user input for user name and password
  • a properties file, web.xml file, or ResourceBundle to keep parameters out of compiled code
  • the jdbc.drivers property of the System class

- no title specified

import java.sql.*;

import javax.naming.*;

import javax.sql.*;

final class GetConnection {

/** Uses JNDI and Datasource (preferred style). */

static Connection getJNDIConnection() {

String DATASOURCE_CONTEXT = "java:comp/env/jdbc/blah";

Connection result = null;

try {

Context initialContext = new InitialContext();

if (initialContext == null) {

log("JNDI problem. Cannot get InitialContext.");

}

DataSource datasource = (DataSource) initialContext

.lookup(DATASOURCE_CONTEXT);

if (datasource != null) {

result = datasource.getConnection();

} else {

log("Failed to lookup datasource.");

}

} catch (NamingException ex) {

log("Cannot get connection: " + ex);

} catch (SQLException ex) {

log("Cannot get connection: " + ex);

}

return result;

}

/** Uses DriverManager. */

static Connection getSimpleConnection() {

// See your driver documentation for the proper format of this string :

String DB_CONN_STRING = "jdbc:mysql://localhost:3306/airplanes";

// Provided by your driver documentation. In this case, a MySql driver

// is used :

String DRIVER_CLASS_NAME = "org.gjt.mm.mysql.Driver";

String USER_NAME = "juliex";

String PASSWORD = "ui893djf";

Connection result = null;

try {

Class.forName(DRIVER_CLASS_NAME).newInstance();

} catch (Exception ex) {

log("Check classpath. Cannot load db driver: " + DRIVER_CLASS_NAME);

}

try {

result = DriverManager.getConnection(DB_CONN_STRING, USER_NAME,

PASSWORD);

} catch (SQLException e) {

log("Driver loaded, but cannot connect to db: " + DB_CONN_STRING);

}

return result;

}

private static void log(Object aObject) {

System.out.println(aObject);

}

}



How to get IP Address in Java ?

Sample Java Code to get IP Address

- no title specified- no title specified

import java.net.InetAddress;

import java.net.UnknownHostException;

public class GetIPAddress {

public static void main(String[] args) {

try {

InetAddress address = InetAddress.getLocalHost();

System.out.println("IP Address is:"+ address.getHostAddress());

} catch (UnknownHostException e) {

e.printStackTrace();

}

}

}

Why is String Immutable ?

String in a class it is used to holding the array of characters. The difference between String and StringBuffer is String is immutable where as StringBuffer is mutable. Means we can not change the value of the string.

Why it so?

Actually in java, Strings are handling in Pool format.

For example:

String str1 = “xyz”;

This string(str1) will be stored into memory in particular address. When we defining new String with same array of characters like

String str2 = “xyz”;

Now JVM will check in String Pool where there is same characters are available or not. If two Strings are match the JVM will refer str1 address to str2. Now the str1 and str2 referring the same characters in same memory location. This is a good idea for increasing memory efficiency.
When we change the str1 characters, the changes will be reflected to str2. Because both str1 and str2 variables are referring the same memory location. For avoiding this we are keeping String as immutable. However we can use StringBuffer if you want to do modifications in the string.

Advantages of Immutablitiy

  • You can share immutable objects between threads without danger of changes confusing the other thread. You don’t need any locking. Two threads can both work on an immutable object at the same time without any possibility of conflict.
  • Once you check the value, you know it has to stay safe. No one can pass you a value, then behind your back swap it to an unsafe one using a background thread. This is particularly important in high security situations where allowing an invalid value to sneak in could compromise system integrity, e.g. a filename. This is probably the main reason that Strings are immutable.
  • You can share duplicates by pointing them to a single instance. You need only one copy, e.g. String interning. This saves RAM. With mutable StringBuilders that were temporarily identical, you could not throw one away, and replace it with a reference to the other, since at any moment their values could diverge again.
  • You can create substrings without copying. You just create a pointer into an existing base String guaranteed never to change. Immutability is the secret behind Java’s very fast substring implementation.
  • Immutable objects are much better suited to be Hashtable keys. If you change the value of an object that is used as a hash table key without removing it and re-adding it you lose the mapping.
  • Since String is immutable, inside each String is a char[] exactly the correct length. Unlike a StringBuilder there is no need for padding to allow for growth.

Garbage Collection Techniques to Enhance Memory Locality in Java Programs


Garbage Collection Techniques to Enhance Memory Locality in Java Programs

James Smith and Min Zhong

Java is a new popular object oriented programming language. Dynamic memory allocation is natural in object oriented programming language. Objects are created (have memory space allocated for them), at run time, used, then die (are no longer referenced and space no longer in use). A feature of Java is that memory is periodically "Garbage Collected" (GC) -- that is, memory space holding dead objects is re-claimed for use by newly created objects. High performance computers use memory hierarchies where objects accessed close together in time are also placed close together in memory. This property is a form of "locality", and good memory locality is critical for high performance. Dynamic memory allocation and GC often have negative effects on the placement of data in memory, and, therefore, the memory locality properties. We plan to study how the conventional memory allocation and GC schemes affect the system performance using a tool from Sun Microsystems (the original Java developers) that provides a dynamic trace of object activity as a program runs, and a software we will develop that models memory allocation/GC algorithms and memory hierarchy. By observing the performance trend and the objects’ characteristics, we can characterize the optimum performance for an ideal algorithm, and get an idea of how much performance improvement can be achieved. We will then be able to come up with some new memory allocation/GC algorithms that could enhance memory locality and improve the system performance.

Java is a new object oriented programming language that is coming into widespread use because it simplifies software development, is platform-independent, and contains built-in security features. Memory allocation in Java is dynamic in nature -- a large number of data objects are created, used, then die (are no longer referenced) throughout the execution of a Java program.

One attractive feature of Java is that the run time system (not the programmer) is responsible for all memory allocation and management. A key part of memory management is the use of automatic "Garbage Collection" (GC). That is, memory space holding dead objects is re-claimed for use by newly created objects without the need for any programmer intervention.

Dynamic memory allocation and garbage collection can have detrimental performance effects, however, because the placement of objects in memory can occur in a rather non-systematic, unpredictable way. In contrast, most computers are dependent on memory data placement for good performance. In particular, high performance computers use memory hierarchies which perform better when data (objects) accessed close together in time are also placed close together in memory -- this is a form of data "locality" that is exploited by cache memories and paged virtual memory systems. On modern systems, memories are organized in a hierarchy, from the top of the pyramid, the small and fast memory, to the bottom, the larger and slower memories, i.e. from caches, to the main memory, to the even slower hard disks. The smaller and expensive memory gives a processor fast data access, while the bottom of the pyramid provides cheap and large capacity at the cost of speed. Due to the limitedness of the amount of the physical resource at the higher end of hierarchy, organizing the placement of data in the fast memory, or preserving the memory locality is essential to high performance.

We plan to study the effects of memory allocation and GC on memory locality in Java programs and to propose new allocation/GC algorithms that will enhance data locality and increase overall system performance.

A number of GC algorithms have been proposed in the literature. A classical algorithm is “Reference Counting” [Collins, 1960], which maintains in each allocated block of memory the number of pointers pointing to that block. The block is freed when the count drops to zero. This algorithm degrades the user program's performance since it has to update the count upon every allocation and takes up space in each block to hold the count. The biggest flaw is that it doesn't detect cyclic garbage.

An often implemented classical algorithm is the "Mark and Sweep" algorithm [McCarthy, 1960]. The algorithm traverses through the whole dynamic memory space, or heap, marks all the live objects, and then "sweeps" all the unmarked "garbage" back to the main memory. The algorithm handles cyclic pointer structures nicely. But once GC is started, it has to go through all the live objects non-stop in order to complete the marking phase. This could potentially slow down other processes significantly, and is probably not desirable in the case of real-time systems or where response time is important (this includes many Java applications). It bears a high cost since all objects have to be examined during the "sweep" phase -- the workload is proportional to the heap size instead of the number of the live objects. Also, data in a mark-swept heap tend to be more fragmented, which may lead to an increase in the size of the program's working set, poor locality and trigger more frequent cache misses and page faults for the virtual memory.

Another classic GC method is the copying algorithm [Minsky, 1963]. The heap (storage where dynamic objects are kept) is divided into two sub-spaces: one containing active objects and the other "garbage". The collector copies all the data from one space to another and then reverses the roles of the two spaces. In the process of copying, all live objects can be compacted into the bottom of the new space, mitigating the fragmentation problem. But the immediate cost is the requirement of the doubled space compared to non-copying collectors. Unless the physical memory is large enough, this algorithm suffers more page faults than its non-copying counterparts. And after moving all data to the new space, the data cache memory will have been swept clean and will suffer cache misses when computation resumes.

A final method, and the one we will use as a starting point is "generational" garbage collection [Appel, 1989]. A generational garbage collector not only reclaims memory efficiently but also compacts memory in a way that enhances locality. This algorithm divides memory into spaces. When one space is garbage collected, the live objects are moved to another space. It has been observed that some objects are long-lived and some are short-lived. By carefully arranging the objects, objects of similar ages can be kept in the same space, thus causing more frequent and small scalar GC's on certain spaces. This could preserve cache locality better than the plain copying algorithm. Its workload is proportional to the number of the live objects in a subspace instead of all in the entire memory space as is the case of "Mark and Sweep".

To support our proposed research, we will be given access to a proprietary tool developed at Sun Microsystems (the original Java developers). This tool provides a dynamic trace of object activity as a Java program runs. We will develop software that models memory allocation/GC algorithms and memory hierarchies. We will then combine the Sun tracing tool and our memory model with a performance analyzing tool that will process the traces to provide data on locality and system performance. The following figure is our proposed structural setting for our study. With the help of the tool and our model, we will be able to first study the impact of the conventional GC schemes on memory locality and on actual system performance when running Java programs.

We will gain some insight into objects referencing behavior and characteristics in relation to memory allocation and GC through this initial study. Using these data, we will next characterize the optimum performance of an ideal GC algorithm, e.g. a generational GC that arranges objects perfectly by their life spans, or via other criteria, thus enhancing memory locality. Such an ideal algorithm will be based on an "oracle" and will therefore be unimplementable, but it will give a limit on how much performance improvement can be achieved. This study will be similar to the way that “Belady's Min” algorithm [Belady, 1966] has been used for studying replacement algorithms in conventional memory hierarchies.

Through our study about the characteristics of optimal GC performance, we hope gain insight that will lead to new implementable algorithms with similar characteristics. Our goal is to define one such algorithm, compare it with the conventional and ideal GC schemes, and measure its performance in term of locality enhancement and system performance improvement.

As a starting point, we have some ideas that might improve the generational GC algorithm. We hypothesize that a majority of the objects that are allocated around the same time tend to have similar life spans. For instance, most objects in an array are likely to be allocated together upon initialization and deserted together when the array is no longer used. As another example, most local objects declared at the beginning of a block of statements, or a scope, are likely to die together when they fall out of the scope. If this hypothesis holds, then we could assume most of the objects in a procedure have a similar life span, and have generation spaces indexed by stack frames. We also propose another correlation: different types of objects tend to have different life spans. How accurate the predictions are and how much this information would actually facilitate an effective GC are the typical questions we plan to examine. If these hypotheses are valid, then we could divide up the generation spaces more accurately, thus facilitating a more efficient GC, improving the memory locality and system performance.

As memory allocation and GC are critical to memory management and the locality, we think this research would be of valuable significance in improving system performance for Java programs (and possibly other object oriented languages). Equipped with ideas and supporting tools, we are confident that our research goals of investigating the automatic dynamic memory management will be fruitful and achievable within the next year.

[Collins, 1960] Geoge E. Collins. “A Method for Overlapping and Erasure of Lists,”

Communications of the ACM, vol.312, pp. 655-657, December 1960.

[McCarthy, 1960] John McCarthy. “Recursive Functions of Symbolic Expressions and Their Computation by

Machine,” Communications of the ACM, vol.3, pp.184-195, 1960.

[Minsky, 1963] Marvin L. Minsky. “A Lisp Garbage Collector Algorithm Using Serial Secondary Storage,”

Technical Report Memo 58(rev.), Project MAC,MIT,Cambridge,MA, December 1963.

[Appel, 1989] Andrew W. Appel. “Simple Generational Garbage Collection and Fast Allocation,”

Software Pratice and Experience, vol.19, no.2, pp.171-183, 1989.

[Belady, 1966] L. A. Belady, “A Study of Replacement Algorithms for a Virtual Storage Computer,”

IBM Systems Journal, vol.5, no.2, pp.78-101, 1966.


Merittrac Question Papers

Merittrac Online Test Questions

I took up a Java test with Merittrac (Chennai). I would like to put down the questions which might be helpful for others.

Others if have attended online test with Merittrac please add the questions you have faced in the comments below.

Section I : Apptitude - 20 Mins
Section I I: Java 15 Questions - 20 Mins
Section IIII : Java Programming - 2 of 3 gives questions - 20 Mins

Section I I:

1. How would garbage collection keep track on live objects and objects without reference

2. How would you enhance garbage collection ? (memory allocation or method of gc like single or gen...)

3. Name the super class of ArrayList and implemented interfaces

4. What is the output of the following code
public class Test {
public static void main(String a[]){
List li = new ArrayList();
li.add(46);
li.add(2);
li.add(new Integer(50));
li.add("List");
li.add(false);
li.add(1.025);
System.out.println(li);
}
}


5. Which of the following are unchecked exceptions (EOFException, NumberFormatException, FileNotFoundException, AssertionError)

6. Name the superclass of AssertionError ? (Thorwable, Error....)

7. Choose one of the option - A constructor cannot (Override, Overload, .....)

8. What will happen from the below code
public class Test {
public static void main(String a[]){
int x = 0;
int y = 50/x;
}
}

9. What will happen in the following code
public class Test {
static{
print(10);
}
public static void print(int x){
try {
System.out.println(x);
} catch (Exception e) {
} finally {
System.out.println("The End");
}
}
}

10. Name the super class of Java
(What a weird question)

11. Is it possible to throw exception from an overridden method

12. What is the output of the below code

public class Test {
public static void main(String a[]){
try {
if(a.length==0)
return;
System.out.println("Try Block...");
} catch (Exception e) {
System.out.println("Exception Block...");
} finally {
System.out.println("Final Block...");
}
}
}

Section III

Have to choose 2 out of 3 and write the program, compile, run and submit the code.

This is quite hard to finish in 20 mins. I completed only one question and the time was out !!!

Rather i would say the editor was too bad and slow. Even mouse provided dint work properly and was ridiculous. It would have been easy to write the code in a notepad rather than typing it in their wonderful test environment.

I choose "Inheritance" and was asked to write a program and compile which meets the below points
  • Write Employee class with id, name, salary, address with getter and setter
  • Override the toString() method and return employee details
  • Override the equals() method and check if same employee
  • Write a Manager class which extends the Employee class
  • This should have setSalary() method and increase the salary by 5% when called.

Thank You !!


Java Memory Model






JSR 133 (Java Memory Model) FAQ
Jeremy Manson and Brian
Goetz, February 2004



Table of Contents




  • What is a memory model, anyway?


  • Do other languages, like C++, have a
    memory model?

  • What is JSR 133 about?

  • What is meant by reordering?

  • What was wrong with the old memory model?

  • What do you mean by incorrectly
    synchronized?


  • What does synchronization do?

  • How can final fields appear to change
    their values?


  • How do final fields work under the new
    JMM?

  • What does volatile do?


  • Does the new memory model fix the
    "double-checked locking" problem?

  • What if I'm writing a VM?

  • Why should I care?




What is a memory model, anyway?




In multiprocessor systems, processors
generally have one or more layers of memory cache, which improves
performance both by speeding access to data (because the data is
closer to the processor) and reducing traffic on the shared memory bus
(because many memory operations can be satisfied by local caches.)
Memory caches can improve performance tremendously, but they present a
host of new challenges. What, for example, happens when two processors
examine the same memory location at the same time? Under what
conditions will they see the same value?



At the processor level, a memory model
defines necessary and sufficient conditions for knowing that writes to
memory by other processors are visible to the current processor, and
writes by the current processor are visible to other processors. Some
processors exhibit a strong memory model, where all processors see
exactly the same value for any given memory location at all
times. Other processors exhibit a weaker memory model, where special
instructions, called memory barriers, are required to flush or
invalidate the local processor cache in order to see writes made by
other processors or make writes by this processor visible to
others. These memory barriers are usually performed when lock and
unlock actions are taken; they are invisible to programmers in a high
level language.



It can sometimes be easier to write
programs for strong memory models, because of the reduced need for
memory barriers. However, even on some of the strongest memory models,
memory barriers are often necessary; quite frequently their placement
is counterintuitive. Recent trends in processor design have encouraged
weaker memory models, because the relaxations they make for cache
consistency allow for greater scalability across multiple processors
and larger amounts of memory.



The issue of when a write becomes
visible to another thread is compounded by the compiler's reordering
of code. For example, the compiler might decide that it is more
efficient to move a write operation later in the program; as long
as this code motion does not change the program's semantics, it is free to do
so. If a compiler defers an operation, another
thread will not see it until it is performed; this mirrors the effect
of caching.



Moreover, writes to memory can be moved
earlier in a program; in this case, other threads might see a write
before it actually "occurs" in the program. All of this
flexibility is by design -- by giving the compiler, runtime, or
hardware the flexibility to execute operations in the optimal order,
within the bounds of the memory model, we can achieve higher
performance.



A simple example of this can be seen in the
following code:


Class Reordering {
int x = 0, y = 0;
public void writer() {
x = 1;
y = 2;
}

public void reader() {
int r1 = y;
int r2 = x;
}
}


Let's say that this code is executed in
two threads concurrently, and the read of y sees the value 2. Because
this write came after the write to x, the programmer might assume that
the read of x must see the value 1. However, the writes may have been
reordered. If this takes place, then the write to y could happen, the
reads of both variables could follow, and then the write to x could
take place. The result would be that r1 has the value 2, but r2 has
the value 0.



The Java Memory Model describes what
behaviors are legal in multithreaded code, and how threads may
interact through memory. It describes the relationship between
variables in a program and the low-level details of storing and
retrieving them to and from memory or registers in a real computer
system. It does this in a way that can be implemented correctly using
a wide variety of hardware and a wide variety of compiler
optimizations.



Java includes several language
constructs, including volatile, final, and synchronized, which are
intended to help the programmer describe a program's concurrency
requirements to the compiler. The Java Memory Model defines the
behavior of volatile and synchronized, and, more importantly, ensures
that a correctly synchronized Java program runs correctly on all
processor architectures.




Do other languages, like C++, have a memory model?





Most other programming languages, such
as C and C++, were not designed with direct support for multithreading.
The protections that these languages offer against the kinds
of reorderings that take place in compilers and architectures are
heavily dependent on the guarantees provided by the threading
libraries used (such as pthreads), the compiler used, and the platform
on which the code is run.




What is JSR 133 about?




Since 1997, several serious flaws have been
discovered in the Java Memory Model as defined in Chapter 17 of the
Java Language Specification. These flaws allowed for confusing
behaviors (such as final fields being observed to change their value)
and undermined the compiler's ability to perform common
optimizations.



The Java Memory Model was an ambitious
undertaking; it was the first time that a programming language
specification attempted to incorporate a memory model which could
provide consistent semantics for concurrency across a variety of
architectures. Unfortunately, defining a memory model which is both
consistent and intuitive proved far more difficult than expected. JSR
133 defines a new memory model for the Java language which fixes the
flaws of the earlier memory model. In order to do this, the
semantics of final and volatile needed to change.



It is surprising, and
sobering, to discover how complicated seemingly simple concepts like
synchronization really are. Fortunately, you need not understand the
details of the formal semantics -- the goal of JSR 133 was to create a
set of formal semantics that provides an intuitive framework
for how volatile, synchronized, and final work.



The goals of JSR 133 include:




  • Preserving existing safety guarantees, like type-safety,
    and strengthening others. For example,
    variable values may not be created "out of thin air": each
    value for a variable observed by some thread must be a value
    that can reasonably be placed there by some thread.

  • The semantics of correctly synchronized
    programs should be as simple and intuitive as possible.

  • The semantics of incompletely or incorrectly
    synchronized programs should be defined so that potential security hazards are
    minimized.

  • Programmers should be able to reason confidently
    about how multithreaded programs interact with memory.


  • It should be possible to design correct, high
    performance JVM implementations across a wide range of popular hardware
    architectures.

  • A new guarantee of initialization safety should
    be provided. If an object is properly constructed (which means that references
    to it do not escape during construction), then all threads which see a
    reference to that object will also see the values for its final fields that
    were set in the constructor, without the need for synchronization.

  • There should be minimal impact on existing code.



What is meant by reordering?




There are a number of cases in which
accesses to program variables (object instance fields, class static
fields, and array elements) may appear to execute in a different order
than was specified by the program. The compiler is free to take
liberties with the ordering of instructions in the name of
optimization. Processors may execute instructions out of order under
certain circumstances. Data may be moved between registers, processor
caches, and main memory in different order than specified by the
program.



For example, if a thread writes to field
a and then to field b, and the value of b
does not depend on the value of a, then the compiler is free
to reorder these operations, and the cache is free to flush b

to main memory before a. There are a number of potential
sources of reordering, such as the compiler, the JIT, and the
cache.



The compiler, runtime, and hardware are
supposed to conspire to create the illusion of as-if-serial semantics,
which means that in a single-threaded program, the program should not
be able to observe the effects of reorderings. However, reorderings
can come into play in incorrectly synchronized multithreaded programs,
where one thread is able to observe the effects of other threads, and
may be able to detect that variable accesses become visible to other
threads in a different order than executed or specified in the
program.



Most of the time, one thread doesn't care what the
other is doing. But when it does, that's what synchronization is for.




What was wrong with the old memory model?




There were several serious problems with
the old memory model. It was difficult to understand, and therefore
widely violated. For example, the old model did not, in many cases,
allow the kinds of reorderings that took place in every JVM. This
confusion about the implications of the old model was what compelled
the formation of JSR-133.



One widely held belief, for example, was
that if final fields were used, then synchronization between threads
was unnecessary to guarantee another thread would see the value of
the field. While this is a reasonable assumption and a sensible
behavior, and indeed how we would want things to work, under the old
memory model, it was simply not true. Nothing in the old memory model
treated final fields differently from any other field -- meaning
synchronization was the only way to ensure that all threads
see the value of a final field that was written by the
constructor. As a result, it was possible for a thread to see the
default value of the field, and then at some later time see its
constructed value. This means, for example, that immutable objects
like String can appear to change their value -- a disturbing prospect
indeed.



The old memory model allowed for
volatile writes to be reordered with nonvolatile reads and writes,
which was not consistent with most developers intuitions about
volatile and therefore caused confusion.



Finally, as we shall see, programmers'
intuitions about what can occur when their programs are incorrectly
synchronized are often mistaken. One of the goals of JSR-133 is to
call attention to this fact.




What do you mean by “incorrectly synchronized”?




Incorrectly synchronized code can mean
different things to different people. When we talk about incorrectly
synchronized code in the context of the Java Memory Model, we mean any
code where




  1. there is a write of a variable by one thread,

  2. there is a read of the same variable by another thread and

  3. the write and read are not ordered by synchronization




When these rules are violated, we say we have a
data race on that variable. A program with a data race is an
incorrectly synchronized program.




What does synchronization do?




Synchronization has several aspects. The
most well-understood is mutual exclusion -- only one thread can hold a
monitor at once, so synchronizing on a monitor means that once one
thread enters a synchronized block protected by a monitor, no other
thread can enter a block protected by that monitor until the first
thread exits the synchronized block.



But there is more to synchronization
than mutual exclusion. Synchronization ensures that memory writes by a
thread before or during a synchronized block are made visible in a
predictable manner to other threads which synchronize on the same
monitor. After we exit a synchronized block, we release the
monitor, which has the effect of flushing the cache to main memory, so
that writes made by this thread can be visible to other threads.
Before we can enter a synchronized block, we acquire the
monitor, which has the effect of invalidating the local processor
cache so that variables will be reloaded from main memory.
We will then be able to see all of the writes made visible by the previous
release.



Discussing this in terms of caches, it
may sound as if these issues only affect multiprocessor
machines. However, the reordering effects can be easily seen on a
single processor. It is not possible, for example, for the compiler to
move your code before an acquire or after a release. When we say that
acquires and releases act on caches, we are using shorthand for a
number of possible effects.



The new memory model semantics create a
partial ordering on memory operations (read field, write field, lock,
unlock) and other thread operations (start and join), where some
actions are said to happen before other operations. When one
action happens before another, the first is guaranteed to be
ordered before and visible to the second. The rules of this ordering
are as follows:




  • Each action in a thread happens before every
    action in that thread that comes later in the program's order.

  • An unlock on a monitor happens before every
    subsequent lock on that same monitor.


  • A write to a volatile field happens before every
    subsequent read of that same volatile.

  • A call to start() on a thread happens
    before any actions in the started thread.

  • All actions in a thread happen before any other
    thread successfully returns from a join() on that thread.




This means that any memory operations
which were visible to a thread before exiting a synchronized block are
visible to any thread after it enters a synchronized block protected
by the same monitor, since all the memory operations happen before the
release, and the release happens before the acquire.



Another implication is that the
following pattern, which some people use to force a memory barrier,
doesn't work:



synchronized (new Object()) {}


This is actually a no-op, and your
compiler can remove it entirely, because the compiler knows that no
other thread will synchronize on the same monitor. You have to set up
a happens-before relationship for one thread to see the results of
another.



Important Note: Note that it is
important for both threads to synchronize on the same monitor in order
to set up the happens-before relationship properly. It is not the case
that everything visible to thread A when it synchronizes on object X
becomes visible to thread B after it synchronizes on object Y. The
release and acquire have to "match" (i.e., be performed on the same
monitor) to have the right semantics. Otherwise, the code has a data
race.




How can final fields appear to change their values?




One of the best examples of how final
fields' values can be seen to change involves one particular
implementation of the String class.



A String can be implemented as an object
with three fields -- a character array, an offset into that array, and
a length. The rationale for implementing String this way, instead of
having only the character array, is that it lets multiple String and

StringBuffer objects share the same character array and avoid
additional object allocation and copying. So, for example, the method
String.substring() can be implemented by creating a new string which
shares the same character array with the original String and merely
differs in the length and offset fields. For a String, these fields
are all final fields.



String s1 = "/usr/tmp";
String s2 = s1.substring(4);


The string s2 will have an offset of 4
and a length of 4. But, under the old model, it was possible for
another thread to see the offset as having the default value of 0, and
then later see the correct value of 4, it will appear as if the string
"/usr" changes to "/tmp".



The original Java Memory Model allowed
this behavior; several JVMs have exhibited this behavior. The new Java
Memory Model makes this illegal.




How do final fields work under the new JMM?




The values for an object's final fields
are set in its constructor. Assuming the object is constructed
"correctly", once an object is constructed, the
values assigned to the final fields in the constructor will be
visible to all other threads without synchronization. In addition, the
visible values for any other object or array referenced by those final
fields will be at least as up-to-date as the final fields.



What does it mean for an object to be
properly constructed? It simply means that no reference to the object
being constructed is allowed to "escape" during
construction. In other words, do
not place a reference to the object being constructed anywhere where
another thread might be able to see it; do not assign it to a static
field, do not register it as a listener with any other object, and so
on. These tasks should be done after the constructor completes, not
in the constructor.



class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}

static void writer() {
f = new FinalFieldExample();
}

static void reader() {
if (f != null) {
int i = f.x;
int j = f.y;
}
}
}


The class above is an example of how
final fields should be used. A thread executing reader is
guaranteed to see the value 3 for f.x, because it is
final. It is not guaranteed to see the value 4 for y, because
it is not final. If FinalFieldExample's constructor looked
like this:



public FinalFieldExample() { // bad!
x = 3;
y = 4;
// bad construction - allowing this to escape
global.obj = this;
}


then threads that read the reference to
this from global.obj are not guaranteed to
see 3 for x.




The ability to see the correctly constructed value for the field is
nice, but if the field itself is a reference, then you also want your
code to see the up to date values for the object (or array) to which
it points. If your field is a final field, this is also guaranteed.
So, you can have a final pointer to an array and not have to worry
about other threads seeing the correct values for the array reference,
but incorrect values for the contents of the array. Again, by
"correct" here, we mean "up to date as of the end of the object's
constructor", not "the latest value available".



Now, having said all of this, if, after a thread constructs an
immutable object (that is, an object that only contains final fields),
you want to ensure that it is seen correctly by all of the other
thread, you still typically need to use synchronization. There is no
other way to ensure, for example, that the reference to the immutable
object will be seen by the second thread. The guarantees the program
gets from final fields should be carefully tempered with a deep and
careful understanding of how concurrency is managed in your code.



There is no defined behavior if you want
to use JNI to change final fields.




What does volatile do?




Volatile fields are special fields which
are used for communicating state between threads. Each read of a
volatile will see the last write to that volatile by any thread; in
effect, they are designated by the programmer as fields for which it
is never acceptable to see a "stale" value as a result of caching or
reordering. The compiler and runtime are prohibited from allocating
them in registers. They must also ensure that after they are written,
they are flushed out of the cache to main memory, so they can
immediately become visible to other threads. Similarly, before a
volatile field is read, the cache must be invalidated so that the
value in main memory, not the local processor cache, is the one
seen. There are also additional restrictions on reordering accesses to
volatile variables.



Under the old memory model, accesses to
volatile variables could not be reordered with each other, but they
could be reordered with nonvolatile variable accesses. This undermined
the usefulness of volatile fields as a means of signaling conditions
from one thread to another.



Under the new memory model, it is still
true that volatile variables cannot be reordered with each other. The
difference is that it is now no longer so easy to reorder normal field
accesses around them. Writing
to a volatile field has the same memory effect as a monitor release,
and reading from a volatile field has the same memory effect as a monitor
acquire. In effect, because the new memory model places stricter
constraints on reordering of volatile field accesses with other field
accesses, volatile or not, anything that was visible to thread A when
it writes to volatile field f becomes visible to thread B when it
reads f.



Here is a simple example of how volatile
fields can be used:



class VolatileExample {
int x = 0;
volatile boolean v = false;
public void writer() {
x = 42;
v = true;
}

public void reader() {
if (v == true) {
//uses x - guaranteed to see 42.
}
}
}


Assume that one thread is calling
writer, and another is calling reader. The write to
v in writer releases the write to x to
memory, and the read of v acquires that value from memory.
Thus, if the reader sees the value true for v, it is also
guaranteed to see the write to 42 that happened before it. This would
not have been true under the old memory model. If v were not
volatile, then the compiler could reorder the writes in

writer, and reader's read of x might see 0.



Effectively, the semantics of volatile
have been strengthened substantially, almost to the level of
synchronization. Each read or write of a volatile field acts like
"half" a synchronization, for purposes of visibility.



Important Note: Note that it is
important for both threads to access the same volatile variable in
order to properly set up the happens-before relationship. It is not
the case that everything visible to thread A when it writes volatile
field f becomes visible to thread B after it reads volatile field

g. The release and acquire have to "match" (i.e., be performed on the
same volatile field) to have the right semantics.




Does the new memory model fix the "double-checked locking"
problem?




The (infamous) double-checked locking
idiom (also called the multithreaded singleton pattern) is a trick
designed to support lazy initialization while avoiding the overhead of
synchronization. In very early JVMs, synchronization was slow, and
developers were eager to remove it -- perhaps too eager. The
double-checked locking idiom looks like this:



// double-checked-locking - don't do this!

private static Something instance = null;

public Something getInstance() {
if (instance == null) {
synchronized (this) {
if (instance == null)
instance = new Something();
}
}
return instance;
}


This looks awfully clever -- the
synchronization is avoided on the common code path. There's only one
problem with it -- it doesn't work. Why not? The most obvious
reason is that the writes which initialize instance and the
write to the instance field can be reordered by the compiler
or the cache, which would have the effect of returning what appears to
be a partially constructed Something. The result would be
that we read an uninitialized object. There are lots of other reasons
why this is wrong, and why algorithmic corrections to it are
wrong. There is no way to fix it using the old Java memory model. More
in-depth information can be found at Double-checked
locking: Clever, but broken
and The

"Double Checked Locking is broken" declaration



Many people assumed that the use of the
volatile keyword would eliminate the problems that arise when
trying to use the double-checked-locking pattern. In JVMs prior to
1.5, volatile would not ensure that it worked (your mileage
may vary). Under the new memory model, making the instance
field volatile will "fix" the problems with double-checked
locking, because then there will be a happens-before relationship
between the initialization of the Something by the
constructing thread and the return of its value by the thread that
reads it.

Redacted -- volatiles are cheap on most platforms.
Instead, use the Initialization On

Demand Holder idiom, which is thread-safe and a lot easier to
understand:



private static class LazySomethingHolder {
public static Something something = new Something();
}

public static Something getInstance() {
return LazySomethingHolder.something;
}


This code is guaranteed to be correct because of the initialization
guarantees for static fields; if a field is set in a static
initializer, it is guaranteed to be made visible, correctly, to any thread that
accesses that class.






Why should I care?



Why should you care? Concurrency bugs
are very difficult to debug. They often don't appear in testing,
waiting instead until your program is run under heavy load, and are
hard to reproduce and trap. You are much better off spending the extra
effort ahead of time to ensure that your program is properly
synchronized; while this is not easy, it's a lot easier than trying to
debug a badly synchronized application.