Introduction to Java Programming Language



Java is a very famous high level programming language. Java was developed at Sun Microsystems in the early 1990s and is based on C++. It looks very similar to C++ but it is significantly simplified as compared to C++. This is the reason why Java is sometimes referred to as C++--. Java is a pure Object Oriented Programming Language. Everything in Java is an object. Java has eliminated many C++ concepts, like multiple inheritance, pointers, structs, enum types, operator overloading, goto statement, etc. Java is a platform independent programming language. Without even a recompile, a Java executable can run on any JVM enabled platform. Java is also network friendly for its portable and threaded nature and because of its rich network libraries. Java provides an extensive support for the development of web and enterprise applications. Servlets, JSP, Applets, JDBC, RMI, EJBs and JSF etc. are some of the Java technologies that are used to build the web and enterprise applications.

Java versus C++:
Generally, Java is more robust than C++. Some of the reasons are:
·         Object handles are initialized to null (a keyword)
·         Handles are always checked and exceptions are thrown for failures
·         All array accesses are checked for bounds violations
·         Automatic garbage collection prevents memory leaks and dangling pointers
·         Type conversion is safer
·         Clean, relatively fool-proof exception handling
·         Simple language support for multithreading
·         Bytecode verification of network applets

Our First Java Program

In this lesson we will learn to write our first Java program. Before doing so, let’s first understand some basics of Java program files.

Java Program Files:

Java program files are very similar to the .c or .cpp program files. In Java the source code is written in the .java file. Each .java source file can contain at most one public class. If there is a public class, then the class name and file name must match. Furthermore, every piece of java code must be the part of a class.

The Java compiler creates Bytecode from the .java program file and stores the same in a .class file. This Bytecode, contained in the .class file, generated by the Java compiler is ready to be executed by the Java Virtual Machine (JVM). For each class in a source file (both public and non-public classes), the compiler creates one ".class" file, where the file name is the same as the class name.
Our First Java Program:
Let’s write our first Java program:
class HelloWorld {               
                   public static void main( String [ ] args )         {                                 
                                    System.out.println("Hello world!");              
     }        
}
You must be glad to see that the above code is very similar to the C or C++ code. When the above code is run after compilation, it simply prints “Hello world!” to the console.
Important points to remember:
·         Function main is the entry point of a java program.
·         Function main is a member of the class.
·         Every class MAY have at most one main function. There may be more than one main function in a Java program, however.
·         The main function must be public static void.
·         The main must have only one argument: an array of String. This array contains the command-line arguments.
·         There is no final semi-colon at the end of the class definition.
Compiling a Java Program File:
We assume that you have downloaded and installed the latest version of JDK (Java Development Kit) from:
http://www.oracle.com/technetwork/java/javase/downloads/index.html

After the installation of JDK, you need to add the bin directory of your java installation to the system path variable, so that the system could find the java compiler and interpreter, whenever needed.
·         When compiling a program, you type the full file name, including the ".java" extension and when running a program, you just type the name of the class whose main function you want to execute.
·         Use javac command to compile your java program files.
C:\ javac helloworld.java

Use java command to run or execute the compiler generated .class files.
C:\ java helloworld

Note that your directory structure may be different from the above.
·         Java has two "categories" of types: primitive types and reference types.

Primitive Types
Primitive data types are generally used for local variables, parameters and instance variables (properties of an object). Primitive data types are located on the stack and we can only access their value, while objects are located on heap and we have a reference to those objects. Also, when invoking methods in java, primitive data types are always passed by value and objects are always passed by reference. All the primitive types have specified sizes that are machine independent for portability. 
 

boolean
same as bool in C++
1 byte in size
char
holds one 16 bit unicode character
2 bytes in size
byte
8-bit signed integer
1 byte in size
short
16-bit signed integer
2 bytes in size
into
32-bit signed integer
4 bytes in size
long
64-bit signed integer
8 bytes in size
float
floating-point number
4 bytes in size
double
double precision floating-point number
8 bytes in size

Reference Types
Arrays and objects of classes are the examples of Java reference types. Arrays and classes are discussed in the coming lessons. There are no struct, union, enum, unsigned, typedef, or pointer types in Java.

Java Arrays vs C++ Arrays

Generally speaking, there is not much difference between the Java and C or C++ arrays. As a C / C++ programmer you will find it very easy to understand and work with arrays in Java.

In C++, when we declare an array, storage for the array is allocated. In Java, when we declare an array, we really only declare a pointer or reference to an array; storage for the array itself is not allocated until we use the "new" keyword. This difference is elaborated below:

C++
into A[10]; // A is an array of length 10
A[0] = 5; // set the 1st element of array A

JAVA
int [ ] A; // A is a reference / pointer to an array
A = new int [10]; // now A points to an array of length 10
A[0] = 5; // set the 1st element of the array pointed to by A

In both C++ and Java we can initialize an array using values in curly braces. Here's the example

Java code:
int [ ] myArray = {13, 12, 11}; // myArray points to an array of length 3
// containing the values 13, 12, and 11

In Java, a default initial value is assigned to each element of a newly allocated array if no initial value is specified. The default value depends on the type of the array element as shown below: 

Type
Value
boolean
false
char
'\u0000'
byte, int, short, long, float, double
0
any reference type e.g. a class object
null

In Java, array bounds are checked and an out-of-bounds array index always causes a runtime error.

Array Operations in Java

Like C and C++, array is a very useful structure in Java programming language too. There are several useful operations, provided by the Java programming language that you can perform on arrays. In this lesson we will show you some of the very useful array operations in java programming language.

Determining the length of an Array in Java:
We can determine the current length of an array (at runtime) using the ".length" operator:
int [ ] A = new int [10];
System.out.println (A.length); // this expression evaluates to 10
A = new int [15];
System.out.println (A.length); // now it evaluates to 15

Copying an Array:
In Java, we can copy an array using the array copy function. Like the output function printing, array copy is provided in java.lang.System, so you must use the name System.arraycopy. The function has five parameters:

src: the source array (the array from which to copy)
scopes: the starting position in the source array
dst: the destination array (the array into which to copy)
dstPos: the starting position in the destination array
count: how many values to copy

Here is an example:

int [ ] A, B;
A = new int[10];
.............// code to put values into A
B = new int[5];
System.arraycopy(A, 0, B, 0, 5) // copies first 5 values from A to B
System.arraycopy(A, 9, B, 4, 1) // copies last value from A into last
//element of B

Note that the destination array must already exist i.e. new must already have been used to allocate space for that array, and it must be large enough to hold all copied values, otherwise you will get a runtime error. Furthermore, the source array must have enough values to copy i.e. the length of the source array must be at least srcPos+count.

For arrays of primitive types, the types of the source and destination arrays must be the same. For arrays of non-primitive types, System.arraycopy(A, j, B, k, n) is OK if the assignment B[0] = A[0] would be OK. The array copy function also works when the source and destination arrays are the same array. For example, you can use it to "shift" the values in an array:

into [ ] A = {0, 1, 2, 3, 4};
System.arraycopy(A, 0, A, 1, 4);

After executing the above code, A has the values: [0, 0, 1, 2, 3].

Multidimensional Arrays:
As in C++, Java arrays can be multidimensional. For example, a 2-dimensional array is an array of arrays. However, a two-dimensional array need not be rectangular. Each row can be of a different length. Here's an example:

int [ ][ ] A; // A is a two-dimensional array
A = new int[5][]; // A now has 5 rows, but no columns yet
A[0] = new int [1]; // A's first row has 1 column
A[1] = new int [2]; // A's second row has 2 columns
A[2] = new int [3]; // A's third row has 3 columns
A[3] = new int [5]; // A's fourth row has 5 columns
A[4] = new int [5]; // A's fifth row also has 5 columns

Java Classes

Classes and Objects are the heart and sould of the OOP (Object Oriented Programming) and without them OOP cannot exist. In this lesson we will start our discussion on Java classes. As C++ programmers, you will glad to know that Java classesare almost the same as C++ classes. Like C++ classes, Java classescontain fields also called instance variables or properties of an object and methods. A field is like a C++ data member, and a method is like a C++ member function.

A Simple Example Class
In the following example, a List is defined to be an ordered collection of items of any type:
class List {   
  // fields       
  private Object [ ] items;    // store the items in an array
  private int  numItems;        // the current # of items in the list
                              
  //methods       

  // constructor function       
  public List() {           
  items = new Object[10];        
  numItems = 0;       
  }                          
                              
  // AddToEnd: add a given item to the end of the list     
  public void AddToEnd(Object ob){
                                
  }
}

In Java, all classes (built-in or user-defined) are (implicitly) subclasses of the classObject. Using an array of Object in the List class allows any kind of Object (an instance of any class) to be stored in the list. However, primitive types (int, char, etc) cannot be stored in the list as they are not inherited from Object.

The Constructor Function

As in C++, constructor functions inJava are used to initialize the instances of a class. They have no return type (not even void) and can be overloaded. You can have multiple constructor functions, each with different numbers and / or types of arguments. If you don't write any constructor functions, a default (no-argument) constructor (that doesn't do anything) will be supplied by the compiler.

If you write a constructor that takes one or more arguments, no default constructor will be supplied and therefore, an attempt to create a new object without passing any arguments will cause a compile-time error.

It is often useful to have one constructor call another. For example, a constructor with no arguments might call a constructor with one argument, passing a default value. This call must be the first statement in the constructor. It is performed using this as if it were the name of the method. For example:

this( 10 );

The above is a call to a constructor that expects one integer argument.

Initialization of fields:
If you don't initialize a field i.e. either you don't write any constructor function, or your constructor function just doesn't assign a value to that field, the field will be given a default value, depending on its type. The default values of different types of variables have been discussed in a previous lesson.


Java Access Specifiers

Each field and method in a class definition has an access level.Keywords private, protected andpublic are used to declare a field and / or method as private, protected and public, respectively. For package level access no modifies is used i.e. if we use no access modifier / specifier, itdefaults to package level access. The following table summarizes different access specifiers / modifiers available in Java programming langauage:

private
accessible only in this class
( no modifier )
accessible only in this package
protected
accessible only in this package and in all subclasses of this class
public
accessible everywhere this class is available

Similarly a class may be declared with the modifier public, in which case the class becomes visible to all classes, everywhere. On the contrary if a class has no modifier (the default, a.k.a. package-private) it becomes visible only within its own package.

For both fields and classes, package access is the default, and is used when no access modifier is specified. Java packages are discussed in the next lesson.

As discussed earlier, access control must be specified for every field and every method; there is no grouping as in C++. For example consider the following piece of code:

public
int x;
int y;

In the above piece of code only x is public; y gets the default, package access.

Static Fields and Methods
Fields and methods can also be declared static. If a field is declared as static, there is only one copy of the field for the entire class, rather than one copy for each instance of the class. A method that is declared as static cannot access any of the non-static fields of the class, and also it cannot call any non-static method. Methods that would be "free" functions in C++ i.e. not members of a class, should be static methods in Java. A public static field or method can be accessed from outside the class, with or without creating an instance of the class.

Final Fields and Methods
Fields and methods can also be declared final. A final method cannot be overridden in a subclass. A final field is like a constant: once it has been given a value, it cannot be assigned to again.

Java Packages

Packages are named groups of related classes. In java the classes can be grouped together in packages. We can specify the package name using a package declaration:

package name ;

The package declaration must be the first (non-comment) line in the .java file. If a file contains a package declaration as above, the file must be in a subdirectory called name i.e. the directory name must match the package name.

We can access public classes in another (named) package using:

package-name.class-name

We can access the public fields and methods of such classes as under:

package-name.class-name.field-or-method-name

We can avoid having to include the package-name using import package-name.* orimport package-name.class-name at the beginning of the file after the package declaration, if any. The former imports all of the classes in the package, and the later imports just the named class. We can have as many import statements as we need. We must still use the class-name to access the classes in the package, and class-name.field-or-method-name to access the fields and methods of the class; the only thing you can leave off is the package name.

Inheritance in Java

From your C++ programming experience you must be aware of the fact that inheritance plays a vital role in Object Oriented Programming. Being a pure object oriented programming language Java also supports inheritance. However, Java directly supports only single inheritance. In other words a sub-class can inherit directly from a single super or parent class. Sub classing from multiple base / super / parent classes is not allowed in Java. This is totally in contrast to C++, where multiple inheritance is allowed.

We use extends keyword to inherit from a super class as under:

public class subClass extends superClass { }

When a class is inherited:
  • All fields and methods are inherited.
  • Public fields and methods of the parent / super class are available to be used in the subclass.
  • Private fields are also inherited, but cannot be accessed by the methods of the subclass.
  • Protected fields can be accessed by the subclass methods.
When the final reserved word is specified on a class specification, it means that class cannot be the parent of any class i.e. a final class cannot be extended.

Each super-class method (except its constructors) can be inherited, overloaded, or overridden, as explained below:

Inherited: If no method with the same name is (re)defined in the subclass, then the subclass has that method with the same implementation as in the super class.

Overloaded: If the subclass defines a method with the same name, but with a different number of arguments or different argument types, then the subclass has two methods with that name: the old one defined by the super class, and the new one defined in the subclass.

Overridden: If the subclass defines a method with the same name, and the same number and types of arguments, then the subclass has only one method with that name: the new one defined in the subclass. A method CANNOT be overridden if it is defined as final in the super class.

Dynamic Binding
In C++, a method must be defined to be virtual to allow dynamic binding. In Java all method calls are dynamically bound unless the called method has been defined to befinal, in which case it cannot be overridden and all bindings are static.

Constructors
A subclass's constructors always call a super class constructor, either explicitly or implicitly. If there is no explicit call (and no call to another of the subclass constructors), then the no-argument version of the superclass constructor is called before executing any statements.

Abstract Classes and Methods

In this lesson we will learn about Abstract Classes and Abstract Methods in Java programminglangauge.

Abstract Methods
An abstract method is a method that is declared in a (super)class, but not defined. In order to be instantiated, a subclass must provide the definition.

Abstract Classes
An abstract class is any class that includes an abstract method. It is similar to Pure virtual in C++. If a class includes an abstract method, the class must be declared abstract, too.

Code Example:
abstract class AbstractClass {
   abstract public void Print();
   // no body, just the function header
}

class MyConcreteClass extends AbstractClass {
   public void Print() {
   // actual code goes here
   }
}
Important points to be remembered:
  • An abstract class cannot be instantiated.
  • A subclass of an abstract class that does not provide bodies for all abstract methods must also be declared abstract.
  • A subclass of a non-abstract class can override a (non-abstract) method of its superclass, and declare it abstract. In that case, the subclass must be declared abstract.

Java Interfaces

As mentioned earlier, multiple inheritances is directly not allowed in Java, however, the same could be achieved through the concept of Interface in Java. Inheritance implements the "is-a" relationship and an interface is similar to a class, but can only contain public, static, final fields (i.e., constants) and public abstract methods (i.e., just method headers, with no bodies).

An interface is declared as shown below:
public interface Employee {
   void RaiseSalary( double d );
   double GetSalary();
}                                
Note that both methods are implicitly public and abstract (those keywords can be provided, but are not necessary in an interface).

A class can implement one or more interfaces (in addition to extending one class). It must provide bodies for all of the methods declared in the interface, or else it must be abstract. For example:
  • public class TA implements Employee {
  •    void RaiseSalary( double d ) {
  •    // actual code here
  •    }
  •    double GetSalary() {
  •    // actual code here
  •    }
  • }
  • Public interfaces (like public classes) must be in a file with the same name. A single class can implement many interfaces at the same time thus achieving multiple inheritance.

    An interface can also be used as a "marker" with no fields or methods. A marker interface is used only to "mark" a class as having a property, and is testable via theinstanceof operator.

Type Conversion in Java

Java is much stronger than C++ in the type conversions that are allowed.

In this lesson we will discussconversions among different primitive types i.e. char, byte, short, int, long, float, and double.

Booleans cannot be converted to other types. For the other primitive types (char, byte, short, int, long, float, and double), there are two kinds of conversion: implicit and explicit.

Implicit conversions:
An implicit conversion means that a value of one type is changed to a value of another type without any special directive from the programmer. A char can be implicitly converted to an int, a long, a float, or a double. For example, the following will compile without error:

char c = 'a';
int k = c;
long x = c;
float y = c;
double d = c;

For the other (numeric) primitive types, the basic rule is that implicit conversions can be done from one type to another if the range of values of the first type is a subset of the range of values of the second type. For example, a byte can be converted to a short, int, long or float; a short can be converted to an int, long, float, or double, etc.

Explicit conversions:
Explicit conversions are done via casting. The name of the type to which you want a value converted is given, in parentheses, in front of the value. For example, the following code casts a value of type double to a value of type int, and a value of type double to a value of type short:

double d = 5.6;
int k = (int)d;
short s = (short)(d * 2.0);

Casting can be used to convert among any of the primitive types except Boolean. Please note that casting can lose information; for example, floating-point values are truncated when they are cast to integers (e.g. the value of k in the code fragment given above is 5).

Useful Java Classes     

In this lesson we will learn about some basic Java classes that are really useful . These useful classes are provided in the java.langpackage.

The first one is the Object class. The Object class is the base class of all the java classes. All Java classes are implicitly derived from the Object class. The Object class provides a number of useful methods like toString() etc. As all classes in Java are implicitly derived from the Object class, all the methods defined in the Object class are automatically available in every Java class.

The second useful Java class is the String class. Like in C++ the String class in Java issued to manipulate text.

String Creation:
String S1 = "hello", // initialize from a string literal
S2 = new String("bye"), // use new and the String constructor
S3 = new String(S1); // use new and a different constructor

String concatenation
String S1 = “hello” + “world”;
String S2 = S1 + “!”;
String S3 = S1 + 10;

The java.lang.String class has many useful methods. If you are interested, just explore the Srtring class in the Java documentation.

Java SDK also provides classes for primitive types. These include: Boolean, Integer, Double, Float etc. Note that variables of type bool, int, double, float etc. are not objects whereas variable of type Boolean, Integer, Double, Float etc. are objects.

Java Classes vs C++ Classes

In C++, when we declare a variable whose type is a class, storage is allocated for an object of that class, and the class's constructor function is called to initialize that instance o f theclass. On the other hand, in Javawhen we declare a variable whose type is a class, we really declare apointer or reference to a class object; no storage is allocated for the classobject, and no constructor function is called unless we use the "new" keyword. This is elaborated with the help of the following example:

Let us assume we have the following class:

class MyClass {
// class definition goes here
}

Let us first look at C++

MyClass m; // m is an object of type MyClass
// the constructor function is called to initialize M.
MyClass *pm; // pm is a pointer to an object of type MyClass
// no object exists yet, no constructor function has been called
pm = new MyClass; // now storage for an object of MyClass has been
// allocated and the constructor function has been called

Now the same thing in Java

MyClass m; // pm is a pointer to an object of type MyClass
// no object exists yet, no constructor function has been called
m = new MyClass(); // now storage for an object of MyClass has been
// allocated and the constructor function has been called. Note
// that you must use parentheses even when you are not
// passing any arguments to the constructor function
// Also note that there is a simple ‘.’ (dot) operator used to
// access members or send message. Java does not use -> operator.

Parameter Passing in Java

In Java, all parameters are passed by value, but for arrays and objects of classes only a reference to the actual parameter, which really is a pointer, is passed. Therefore changing an array element or a class field inside the function does change the actual parameter's element or field. Being a programmer, this demands extra care from you. This would become clearer as you go through the following code examples of parameter passing by value and parameter passing by reference in Java:

PARAMETER PASSING BY REFERENCE:
void f( int [ ] A ) {           
   A[0] = 10;            // change an element of parameter A
}

void g() {
   int [ ] B = new int [3];
   B[0] = 5;
   f(B);
                                              // B[0] is now 10, because function f changed the
                                              // first element of the array
}
PARAMETER PASSING BY VALUE:
void f( int A ) {
   A = 10;                // change the value of parameter A to 10
}

void g() {
   int B =  5;
   f(B);
                                              // B has not changed even though the function f changed the
                                              // value to 10
}

Exception Handling in Java 1

Exception handling in Java is based on C++ but is designed to be more in line with OOP. It includes a collection of predefined exceptions that are implicitly raised by the JVM. All java exceptions are objects of classes that are descendents of Throw able class. There are two predefined subclasses of Throw able: Error and Exception.

Error and its descendents are related to errors thrown by JVM, e.g. out of heap memory. Such an exception is never thrown by the user programs and should not be handled by the user.

User programs can define their own exception classes. Convention in Java is that such class’s subclass the Exception class. There are two predefined descendents of Exception class: IOException and Runtime Exception. IOException deals with errors in I/O operations. In the case of RuntimeException there are some predefined exceptions which are, in many cases, thrown by JVM for errors such as out of boundsexception, and Null pointer exception.

Checked and Unchecked Exceptions
Exceptions of class Error and RuntimeException are called unchecked exceptions. They are never a concern of the compiler. A program can catch unchecked exceptions but it is not required. All others are checked exceptions. Compiler ensures that all the checked exceptions a method can throw are either listed in its throws clause or are handled inside the method.
We will continue our discussion on Exception handling in this lesson. In this lesson we will learn to codeException handlers.

Exception Handler
Exception handler in Java is similar to C++ except that the parameter of every catch must be present and its class must be descendent of Throwable. The syntax of try is exactly same as C++ except that there is an optional finally clause as well.

Consider the following example:
class MyException extends Exception {
   public MyException() { }
   public MyException(String message) {
      super (message);
   }
}
This exception can be thrown with
throw new MyException();

Or

MyException myExceptionObject = new MyException();
throw myExceptionObject;

Binding of exception is also similar to C++. If an exception is thrown in the compound statement of try construct, it is bound to the first handler (catch function) immediately following the try clause whose parameter is the same class as the thrown object or an ancestor of it. Exceptions can be handled and then re-thrown by including a throw statement without an operand at the end of the handler. To ensure that exceptions that can be thrown in a try clause are always handled in a method, a special handler can be written that matches all exceptions. For example:

catch (Exception anyException) {
}

Exception Handling in Java 3

In this lesson we will continue our discussion on exception handling inJava programming langauge.

During program execution, the Java runtime system stores the class name of every object. getClass() can be used to get an object that stores the class name. It has a getName() method. The name of the class of the actual parameter of the throw statement can be retrieved in the handler as shown below.

anyException.getClass().getName();

In the case of a user defined exception, the thrown object could include any number of data fields that might be useful in the handler.

throws Clause
The throws clause is overloaded in C++ and conveys two different meanings: one asspecification and the other as command. Java is similar in syntax but different in semantics. The appearance of an exception class name in the throws clause of Java method specifies that the exception class or any of its descendents can be thrown by the method.

A C++ program unit that does not include a throws clause can throw any exceptions. A Java method that does not include a throws clause cannot throw any checked exception, it does not handle. A method cannot declare more exceptions in its throws clause than the methods it overrides, though it may declare fewer. A method that does not throw a particular exception, but calls another method that could throw the exception, must list the exception in its throws clause.

The finally clause
A Java exception handler may have a finally clause too. A finally clause always executes when its try block executes (whether or not there is an exception). The use of try, catch and finally is presented below:
try {
}
catch () {

}
finally {
}
A finally clause is usually included to make sure that some clean-up (e.g. closing opened files) is done.

Exception Handling in Java 4

In this lesson we will conclude our discussion on exception handling in Java programming language.

There is something more to understand about the finally clause in order to use it effectively. If the finally clause includes a transfer of control statement (return, break, continue, throw) then that statement overrides any transfer of control initiated in the try or in a catch clause.

First, let's assume that the finally clause does not include any transfer of control. Here are the situations that can arise:
  • No exception occurs during execution of the try, and no transfer of control is executed in the try. In this case the finally clause executes, then the statement following the try block.
  • No exception occurs during execution of the try, but it does execute a transfer of control. In this case the finally clause executes, and then the transfer of control takes place.
  • An exception does occur during execution of the try, and there is no catch clause for that exception. Now the finally clause executes, then the uncaught exception is "passed up" to the next enclosing try block, possibly in a calling function.
  • An exception does occur during execution of the try, and there is a catch clause for that exception. The catch clause does not execute a transfer of control. In this case the catch clause executes, then the finally clause, then the statement following the try block.
  • An exception does occur during execution of the try, there is a catch clause for that exception, and the catch clause does execute a transfer of control. Here, the catch clause executes, then the finally clause, then the transfer of control takes place.

If the finally block does include a transfer of control, then that takes precedence over any transfer of control executed in the try or in an executed catch clause. So for all of the cases listed above, the finally clause would execute, then its transfer of control would take place. Here's one example:
try {
   return 0;
}
finally {
   return 2;
}
The result of executing this code is that 2 is returned. Note that this is rather confusing! The moral is that you probably do not want to include transfer-of-control statements in both the try statements and the finally clause, or in both a catch clause and the finally clause.

Java Threads

Java supports concurrency through threads which are lightweight processes. A thread is similar to a real process in that a thread and a running program are threads of execution. A thread takes advantage of the resources allocated for that program instead of having to allocate those resources again. A thread has its own stack and program counter. The code running within the thread works only within the context implied by the stack and PC, also called an execution context.

Creating Java Threads
There are two ways to create our own Thread object:
  1. Sub classing the Thread class and instantiating a new object of that class
  2. Implementing the Runnable interface
In both cases the run() method should be implemented. This is elaborated with the help of following examples:

Example of Extending Thread
public class Thread Example extends Thread {
   public void run () {
      for (int i = 1; i <= 100; i++) {
         System.out.println(“Thread: ” + i);
                 }
   }
}
Example of Implementing Runnable
public class Runnable Example implements Runnable {
   public void run () {
      for (int i = 1; i <= 100; i++) {
         System.out.println (“Runnable: ” + i);
      }
   }
}
It may be noted that both of these are very similar to each other with minor syntactic and semantic differences.

Starting the Threads
A thread is started by simply sending the start message to the thread. This is shown in the following example:
public class ThreadsStartExample {
   public static void main (String argv[]) {
      new ThreadExample ().start ();
      new Thread(new RunnableExample ()).start ();
   }
}

Java Threads 2

Thread Methods
Some of the common thread methods are listed below:
  • start()
  • sleep()
  • yield()
  • run()
  • wait()
  • notify()
  • notifyAll()
  • setPriority()

Thread Synchronization - Wait and Notify
Threads are based upon the concept of a Monitor. The wait() and notify() methods are used just like wait and signal in a Monitor. The following example of a producer-consumer problem elaborates the concept of thread synchronization and sharing objects between threads inside a single Java program:
class Buffer {
   private int [ ] buf;
   private int head, tail, max, size;

   public Buffer (int buf_size) {
      buf = new int [buf_size];
      head =0; tail = 0; size = 0;
      max = buf_size;
   }
              
   public synchronized void deposit (int item) {
      try {
         while (size ==max) wait();
                                buf [tail] = item;
                                tail = (tail + 1) % max;
                                size++;
                                notify();
                }
      catch
                    (interruptedException e) {
                                // exception handler
                }
   }

   public synchronized int fetch() {
      int item = 0;
                 try {
                               while (size == 0) wait();
                               item = buf [head] ;
                               head = (head + 1) % max;
                               size--;
                               notify();
                }
                catch (interruptedException e) {
                               // exception handler
                }
               return item;
   }
}

class Producer extends Thread {
   private Buffer buffer;

   public Producer (Buffer buf) {
      buffer = buf;
   }

   public void run () {
      int item;
      while (true) {
                              // create a new item
                               buffer.deposit(item);
                 }
  }
}

class Consumer implements Runnable  {
   private Buffer buffer;

   public Consumer (Buffer buf) {
      buffer = buf;
   }

   public void run () {
      int item;
      while (true) {
         item = buffer.fetch();
                                // consume item
                }
  }
}
We can now instantiate these threads as shown below:
Buffer buffer = new Buffer(100);
Producer producer1 = new Producer(buffer);
Consumer comsumer = new Consumer(buffer);
Thread consumer1 = new Thread(consumer);
producer1.start(); consumer1.start();

In this case the buffer is a shared variable used by both producer and consumer.

notify() and notifyAll()
There is a slight difference between notify() and notifyAll(). As the name suggest, notify() wakes up a single thread which is waiting on the object's lock. If there is more than one thread waiting, the choice is arbitrary i.e. there is no way to specify which waiting thread should be re-awakened. On the other hand, notifyAll() wakes up ALL waiting threads; the scheduler decides which one will run.