Monday, September 17, 2012

JDK JRE JVM

When we say Java is Platform independent, we mean that same code can run seamlessly on Windows/Linux/Mac machines. We need not change our code or make any special provision in the code to run it on different machines. Such provision is very common in C/C++ code (like porting the code from Windows to Linux), where we instruct the program to run certain parts in linux and bypass them while running on Windows and vice-versa. Its not the case with Java. This is achieved by three simple terms that we will discuss here JDK JRE JVM, the eternal triumvirate.
The relationship can be understood by the diagram below, which we will explore in detail.
jdkjrejvm1

JVM (Java Virtual Machine)

It is primarily JVM that makes Java platform independent. As the name suggests it is a Java Virtual MachineReal Machine is the linux box (real piece of hardware) on which we run our application. Virtual Machine is a layer on top of the real hardware. For those who interact with it, JVM acts as though it is the real boss (Machine). But in reality it’s just a Software Hoax.
Like any Computing Machine, it comes with the caravan of instruction sets and power to play with memory. For different platforms (Windows/Linux/Mac), we have different implementations of JVM. These interact with different Machines in different ways but provide a uniform Virtual Environment. Java program needs to interact just with this Virtual Machine and not the Real Machine, making Java Platform independent. Different JVM implementations might differ, mostly in areas which are not covered by specification provided by Java and does not affect the results of a Java program. These are areas like garbage collection, performance etc.
JVM takes  Java bytecode as input, which it interprets into Machine code compatible to specific Hardware on which JVM is running. To run a program JVM uses class libraries and java.exe provided in the JRE.
Java Bytecode: JVM does not understand *.java files. JDL compiled *.java files and create *.class files, which contain bytecode and understood by JVM. If we take the same bytecode and run it on different enviroments, due to the JVM which is uniform, we will get same results.
This make life simpler for developers,  isn’t it? Why worry about where the code will run. Just write the code and be done.
Compiler compiles the code in a bytecode for a Virtual Processor (JVM) which in turn converts it into Machine code for a Real Processor (LinuX/Windows platform).

JRE (Java Runtime Environment)

Various implementations of JVM which are installed on various Platforms are called JRE (Java Runtime Environment). This is the software which runs and interact with the Real Hardware and provide a JVM. It also contains the libraries required to run applications. Note that it cannot complie the code. It can just provide JVM and libaries which can run a comiled code (bytecode). For compiling the code we need JDK.
In effect JRE = JVM + Few Java packages + Runtime libaries (java.exe)
How it happens is, JVM will run a program using runtime libararies and other files which are there in a JRE. If JRE is missing you cannot run a Java program.

JDK (Java Developer Kit)

This is the Ace among the three. It contains JRE, JVM and compiler (javac.exe) along with other things. With JDK one is able to compile (convert *.java to *.class bytecode) and run (java.exe) a program. It is maily for developers. Without JDK installed there is no point writing a Java code as you will not be able to compile and test it.
Normally if you get a Windows machine to work on, you wont find JDK installed by default. You would just be having JRE (required to run online games which were complied by JDK). Apart from that a lot of softwares we want to run on Windows have JDK compiled code which again requires JRE to run. We need to install JDK separately.
Source code (Test.java) is converted to Test.class (bytecode) by javac.exe compiler tool. Then java.exe (application launcher in JRE) runs it on JVM (which converts bytecode to machine code and run it on OS).

Monday, July 16, 2012

JAVA.UTIL.CONCURRENT BLOCKINGQUEUE INTERFACE

This interface extends Queue interface (which in turn extends Collection interface). All implementations of Blocking Queue are Thread-Safe. Blocking terminology comes from the fact that BlockingQueue provides methods which can make the calling Thread to Wait before proceeding further.

Consumer Thread

If the Queue is empty, the Consumer Thread does not have to explicitly check for the emptiness (and write code to wait() till it becomes non-empty), BlockingQueue provided methods which encapsulate all this. Makes life simpler. So if the Queue is empty, consumer Thread will WAIT, till some element is inserted in the Queue.
1. take(): Just as in a Queue following FIFO, it removes and returns the head. If Queue is empty, it will make the Thread to WAIT till an element becomes available.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Taking example of Continuous Consumer
Queue simpleQueue = new ArrayDeque(10);
...
...
while (true) {
    synchronized (simpleQueue) {
        while (simpleQueue.isEmpty()) {
            simpleQueue.wait();
        }
        simpleQueue.remove();
    }
}
//This can be simplified to below
BlockingQueue blockingQueue = new ArrayBlockingQueue(10);
...
...
while(true) {
    blockingQueue.take(); //Waits till Queue becomes non empty. While loop not continuous
}
2. poll(): Just as in a Queue following FIFO, it removes and returns the head. If Queue is empty, it returns a null. No Blocking here.
1
2
3
while(true) {
    blockingQueue.poll(); //Wont make the Thread WAIT, Continuous while loop
}
3. poll(TIMEOUT): Just as in a Queue following FIFO, it removes and returns the head. If Queue is empty, it will make the Thread to WAIT till the specified  TIMEOUT or till an element becomes available (whichever comes first). Returns null in case it waits till TIMEOUT.
4. remove(object): Just as a Collection, it removes element from Queue when element.equals(object). If more than one element are equal, the one closer to HEAD is removed. Returns TRUE if found, FALSE otherwise. In case of multiple elements which element is removed can be checked with the following code.
1
2
3
4
5
6
7
8
9
10
11
12
BlockingQueue blockingQueue = new ArrayBlockingQueue(10);
blockingQueue.put("1");
blockingQueue.put("2");
blockingQueue.put("1");
blockingQueue.put("3");
System.out.println("Before: " +blockingQueue);
blockingQueue.remove("1");
System.out.println("After: "+ blockingQueue);
Output:
Before: [1, 2, 1, 3]
After: [2, 1, 3]

Producer Thread

Similarly, there are methods to insert in the Queue, whereby we don’t have to write code to check if Queue is full not (and wait() till it has some space free). All this is provided to us already. So if the Queue is full, producer Thread will WAIT, till some element is deleted from the Queue.
1. put(object): Just as in a Queue, inserts the object to the tail. Will make the Thread to WAIT till BlockingQueue is full (specified size for the bounded Queues or Integer.MAX_VALUE for unbounded Queues). Once space is available, inserts the object.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Taking example of Continuous Producer
Queue simpleQueue = new ArrayDeque(10);
...
...
while (true) {
    synchronized (simpleQueue) {
        while (simpleQueue.size() == 10) {
            simpleQueue.wait();
        }
        simpleQueue.add("1");
    }
}
//This can be simplified to below
BlockingQueue blockingQueue = new ArrayBlockingQueue(10);
...
...
while(true) {
    blockingQueue.put("1"); //Waits till space becomes available. While loop not continuous
}
2. add(object):  Just as in a Queue, it inserts the object at the tail. If Queue is full, it throws an Exception, else returns TRUE. No Blocking here.
3. offer(object): Just as in a Queue, it inserts the object at the tail. If Queue is full, it returns a FALSE, else TRUE. No Blocking here.
4. offer(TIMEOUT): Just as in a Queue, it inserts the object at the tail. If Queue is full, it will make the Thread to WAIT till the specified  TIMEOUT or till the space becomes available (whichever comes first). Returns FALSE in case it waits till TIMEOUT, TRUE other wise.

Points to Note

1. null elements are not allowed in the BlockingQueue. Remember poll() returns null if Queue is Empty. Hence this restriction.
2. addAll(..) type bulk operations methods inherited from Collection Interface are not atomic. So it might happen that post adding couple of elements, Queue becomes full and fails to add anymore, throwing an IllegalStateException.