It's all about Java: threads
Showing posts with label threads. Show all posts
Showing posts with label threads. Show all posts

Wednesday, 31 January 2018

Core Java: Immutable objects and mutable objects with an example

Immutable objects and mutable objects with an example 


In object oriented programming language in short OOPS, every problem, precisely every requirement is viewed as an object. Understanding the problem in this point of view brings many good things possible in programming like encapsulation, abstraction, polymorphism and inheritance. Anyways this post is not intended for describing benefits of OOPS.

Object could be any thing. Let us take Car for an instance. Basically car is an object and it has name, wheels, metal body, engine, maximum speed,  gear box etc as properties.

Let us consider the car name is Ferrari, maximum speed is 200 km per hr with 6 gears. While driving the car driver can change the speed of the car and change the gear etc.
So while car is running it's current speed, current gear are considered to be state of the object.
The current speed can be changed using accelerator and gear can be changed using gear box. These can be considered as behavior of the car object. Of course car has a name as well.

 Every object has 3 characteristics they are State, Behavior and Name. 

In our example Ferrari is name of the object. Number of gears, current gear, current speed are State and accelerator and gear box decides the behavior of the car object. In java language object's reference name is name of object and methods which decides state are behavior.  

ImmutableObject ferrari = new ImmutableObject("Ferrari", 200, "Red");

             1. new operator creates the object
             2. ferrari is name of object
             3. Ferrari, 200, and Red are State of object

Objects based upon it's behavior can be categorized into two types. They are 
              1. Immutable objects and 
              2. Mutable objects


Mutable and Immutable objects



Mutable object's state can be changed at run time, where as immutable object's state can not be changed. String class is the ideal example for immutable objects. 
    
The state of an object can be decided at it's creation time or at run time or at both times. If state is decided at creation time and it is restricted not be changed at run time, this object is considered to be an  immutable object. If this can be changed at run time, it is called as mutable object.

If car is automatic [no gears] and it's speed can not be changed at any time, then it is immutable car object.  

Below program creates immutable objects:




01  public final class ImmutableObject {
02
03  private String name;
04
05  private int maxSpeed;
06
07  private String color;
08
09  /**
10  * @param name
11  *            holds car name
12  * @param maxSpeed
13  *            holds maximum speed of the car
14  * @param color
15  *            holds color of car
16  */
17  public ImmutableObject(String name, int maxSpeed, String color) {
18  this.name = name;
19  this.maxSpeed = maxSpeed;
20  this.color = color;
21  }
22
23  public String getName() {
24  return name;
25  }
26
27  public int getMaxSpeed() {
28  return maxSpeed;
29  }
30
31  public String getColor() {
32  return color;
33  }
34
35  public static void main(String[] args) {
36  ImmutableObject ferrari = new ImmutableObject("Ferrari", 200, "Red");
37  System.out.println("Car name: " + ferrari.getName());
38  System.out.println("Car color:" + ferrari.getColor());
39  System.out.println("Car maximum speed:" + ferrari.getMaxSpeed());
40  System.out.println();
41
42  ImmutableObject anotherCar = new ImmutableObject("BMW", 180, "White");
43  System.out.println("Car name: " + anotherCar.getName());
44  System.out.println("Car color:" + anotherCar.getColor());
45  System.out.println("Car maximum speed:" + anotherCar.getMaxSpeed());
46  }
47  }
48

Output:

Car name: Ferrari
Car color:Red
Car maximum speed:200

Car name: BMW
Car color:White
Car maximum speed:180

Explanation


Line 1: First and fore most rule is to make your class final class.

Line 3 to Line 7: All variables are private variables. private access modifier restrics usage of members within the class

Note: Do not use other classes as data types of your instance variables which are mutable in behavior. All of our example variables are of String type. String is immutable. See API document of String class for more information.   


Line 17: Creates parameterised constructor with state which can not be changed at run time

Line 23 to Line 33: Create only those methods which shares it's state to the other classes. As we did in our example ImmutableObject. Allows only getter methods and no setter methods at all.


Line 36 to Line 42: Finally, create 2 objects ferrari and another car with different state which can not be changed at run time..

Now, let us change the same class which allows creating mutable objects:

01
02 public class MutableObject {
03
04 private String name;
05
06 private int maxSpeed;
07
08 private String color;
09
10 private int currentGear;
11
12 private int currentSpeed;
13
14 /**
15 * @param name
16 *            holds car name
17 * @param maxSpeed
18 *            holds maximum speed of the car
19 * @param color
20 *            holds color of car
21 */
22 public MutableObject(String name, int maxSpeed, String color) {
23 this.name = name;
24 this.maxSpeed = maxSpeed;
25 this.color = color;
26 }
27
28 public String getName() {
29 return name;
30 }
31
32 public int getMaxSpeed() {
33 return maxSpeed;
34 }
35
36 public int getCurrentGear() {
37 return currentGear;
38 }
39
40 public void setCurrentGear(int currentGear) {
41 this.currentGear = currentGear;
42 }
43
44 public int getCurrentSpeed() {
45 return currentSpeed;
46 }
47
48 public void setCurrentSpeed(int currentSpeed) {
49 this.currentSpeed = currentSpeed;
50 }
51
52 public String getColor() {
53 return color;
54 }
55
56 public static void main(String[] args) {
57 MutableObject ferrari = new MutableObject("Ferrari", 200, "Red");
58 System.out.println("Car name: " + ferrari.getName());
59 System.out.println("Car colo: " + ferrari.getColor());
60 System.out.println("Car maximum speed:" + ferrari.getMaxSpeed());
61
62 ferrari.setCurrentGear(5);
63 ferrari.setCurrentSpeed(150);
64 System.out.println(String.format("Current speed is %s and current gear is %s \n", ferrari.getCurrentSpeed(), ferrari.getCurrentGear()));
65
66
67 ferrari.setCurrentGear(1);
68 ferrari.setCurrentSpeed(10);
69 System.out.println(String.format("Changed state at run time!.. \nCurrent speed is %s and current gear is %s ", ferrari.getCurrentSpeed(), ferrari.getCurrentGear()));
70
71
72 System.out.println();
73
74 }
75}
76

Output:


Car name: Ferrari
Car colo: Red
Car maximum speed:200
Current speed is 150 and current gear is 5 

Changed state at run time!.. 
Current speed is 10 and current gear is 1 


Explanation

  

Line 2: Remove final keyword. This makes the class extendable using extend keyword

Line 10 to Line 12: Introduced new variables which adds new information to the state of object

Line 40 and Line 48: Introduced new setter methods which changes state at run time.

Line 57: Finally, create the ferrari object and change it's state run time by calling different setter methods.

Line 62 to Line 72: Changes the state by calling setters on member variables.  

Few more details about immutable objects:


  • It is always good practice to use immutable objects in our application especially in concurrent apps where ever applicable
  • Immutable objects ensures correct results/output always in all environments like multi threading environment, collection framework.
  • HashMap<key, value> always requires immutable object as key. Otherwise it behaves in undetermined way.
  • Consider cloning when creating immutable classes. I will post another article about importance of deep cloning and shallow copy in details in near future.
  • Cache memory implementation uses immutable objects 
  • java.lang.String is the most used immutable class in java

    .

Sunday, 28 January 2018

Java Multi threaded programming basics with Reentrant lock

Java Multi threaded programming basics with Reentrant locks

As we have seen in earlier post that implicit locking mechanism achieved using synchronized keyword slows down the application performance. Hence java concurrency api gives explicit locking mechanism to achieve mutual exclusion among shared object.

How using explicit locks are better than implicit lock?


  • Explicit lock acquires lock per Thread basis and not per method invoke basis. It is inverse in the case of implicit lock.  
  • If a method is synchronized then every invocation of that method involves acquiring and releasing of lock. This process really slows down the application performance. 
  • Hence it is always good idea to prefer reentrent lock or explicit lock to implicit lock.
  • ReentrantLock is a class available in java.util.concurrency package
  • lock() and unlock() methods are used used to acquire and release the lock.
  • Condition class is used in place of Object class wait(), notifyAll() and notify().
  • signal() and await() of Condtion are used mostly 
Let's see the  Java Multi threaded programming basics Producer and Consumer Problem's solution with Reentrent lock.


import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * In {@code BufferImpl} we have seen thread safe 
 * buffer implementation using implicit lock/ synchronization block
 * 
 * This {@code BufferImpl_conc} we see same implementation replacing implicit
 * lock with concurrency utility classes Reentrant Locks
 * 
 * Buffer implementation with ArrayList and with Producer consumer 
 * problem implementation
 * 
 * @author Nagasharath
 *
 */
public class BufferImpl_conc {

   private CopyOnWriteArrayList<String> buffer;
   private final short SIZE = 10;
   private boolean isBufferFull = false;
   private ReentrantLock lock;
   private Condition condition;

  public BufferImpl_conc() {
     buffer = new CopyOnWriteArrayList<String>();
     lock = new ReentrantLock();
     condition = lock.newCondition();
  }

 /**
  * @throws InterruptedException
  */
 private void producesFeed() throws InterruptedException {
    lock.lock();
    try {
       while (true) {
         if (isBufferFull) {
             System.out.println("Started Consuming!....\n");
             condition.signal();
             condition.await();
        }
        buffer.add(String.valueOf(System.nanoTime()));
        if (SIZE <= buffer.size()) {
              isBufferFull = true;
              Thread.sleep(10000);
              System.out.println("Buffer full. Production halts...\n");
       }
     }
    } finally {
        lock.unlock();
    }
 }

 /**
  * @throws InterruptedException
  */
 private void consumesFeed() throws InterruptedException {
    lock.lock();
    try {
       while (true) {
          Iterator<String> iter = buffer.iterator();
          while (iter.hasNext()) {
             String next = iter.next();
             System.out.println("Consuming element: " + next);
             buffer.remove(buffer.indexOf(next));
          }
          isBufferFull = false;
          System.out.println("Started producing!....");
          condition.signal();
          condition.await();
      }
   } finally {
      lock.unlock();
   }
 }
 /**
  * @author Nagasharath
  *
  */
 class ProducerThread extends Thread {
     @Override
    public void run() {
      try {
        producesFeed();
      } catch (InterruptedException e) {
      }
  }
 }

 /**
  * @author Nagasharath
  *
  */
 class ConsumerThread extends Thread {
  @Override
  public void run() {
    try {
      consumesFeed();
    } catch (InterruptedException e) {
    }
  }
 }
 public static void main(String[] args) {
   BufferImpl_conc impl = new BufferImpl_conc();
   ProducerThread producerThread = impl.new ProducerThread();
   ConsumerThread consumerThread = impl.new ConsumerThread();
   producerThread.start();
   consumerThread.start();
 }
}

Most parts of the program are same as we used in the post Java Multi threaded programming basics It is advised to read my post  Java Multi threaded programming basics before reading this. I try to explain changes from earlier post program here

  1 private final short SIZE = 10;
  2 private boolean isBufferFull = false;
  3 private ReentrantLock lock;
  4 private Condition condition;

Line 3: Instance of ReentrantLock is similar to synchronized keyword locking but it is more intelligent.
Line 4: Condition instance has methods which replaces Object class wait and notify() methods.

  1  public BufferImpl_conc() {
  2     buffer = new CopyOnWriteArrayList<String>();
  3     lock = new ReentrantLock();
  4     condition = lock.newCondition();
  5  }
Line 3 and Line 4: Instantiates lock and condition Objects

 1 private void producesFeed() throws InterruptedException {
 2   lock.lock();
 3    try {
 4      while (true) {
 5         if (isBufferFull) {
 6             System.out.println("Started Consuming!....\n");
 7             condition.signal();
 8             condition.await();
 9         }
 10         buffer.add(String.valueOf(System.nanoTime()));
 11         if (SIZE <= buffer.size()) {
 12           isBufferFull = true;
 13           Thread.sleep(10000);
 14           System.out.println("Buffer full. Production halts...\n");
 15         }
 16       }
 17     } finally {
 18          lock.unlock();
 19     }
 20 }
Line 1: await() at line 8 throws InterruptedException
Line 2: lock.lock() statement is equal to the synchronized(this)  {  . . .  }
Line 7: condition.signal() notifies the waiting thread on same object to start it's execution
Line 8: condition.await() makes current thread to wait on isBufferFull == true condition check
Line 17 to Line 19: lock.unlock() must be called in finally block always

Output:  


Buffer full. Production halts...

Started Consuming!....

Consuming element: 2838231927112595
Consuming element: 2838231927212435
Consuming element: 2838231927229502
Consuming element: 2838231927238888
Consuming element: 2838231927246995
Consuming element: 2838231927254675
Consuming element: 2838231927261075
Consuming element: 2838231927267902
Consuming element: 2838231927274302
Consuming element: 2838231927281555
Started producing!....
Buffer full. Production halts...

Started Consuming!....

Consuming element: 2838242029132348
Consuming element: 2838242029210428
Consuming element: 2838242029244561
Consuming element: 2838242029271015
Consuming element: 2838242029386215
Consuming element: 2838242029448935
Consuming element: 2838242029479228
Consuming element: 2838242029504401
Consuming element: 2838242029529148
Consuming element: 2838242029553895
Started producing!....
Buffer full. Production halts...

Started Consuming!....

Consuming element: 2838252029524881
Consuming element: 2838252029547921
Consuming element: 2838252029556881
Consuming element: 2838252029563281
Consuming element: 2838252029568401
Consuming element: 2838252029573521
Consuming element: 2838252029578215
Consuming element: 2838252029582908
Consuming element: 2838252029588028
Consuming element: 2838252029593148
Started producing!....
Buffer full. Production halts...

Started Consuming!....

Consuming element: 2838262032106639
Consuming element: 2838262032149732
Consuming element: 2838262032165092
Consuming element: 2838262032193252
Consuming element: 2838262032204772
Consuming element: 2838262032214585
Consuming element: 2838262032223972
Consuming element: 2838262032233359
Consuming element: 2838262032241892
Consuming element: 2838262032251279
Started producing!....
Buffer full. Production halts...

Started Consuming!....

Consuming element: 2838272040024285
Consuming element: 2838272040065245
Consuming element: 2838272040077619
Consuming element: 2838272040086152
Consuming element: 2838272040093832
Consuming element: 2838272040101512
Consuming element: 2838272040108766
Consuming element: 2838272040115592
Consuming element: 2838272040122845
Consuming element: 2838272040130099
Started producing!....

 

Saturday, 27 January 2018

Java Multi threaded programming basics


All modern computer hardware architectures and operating systems are capable and optimized for multi processor system and multi threaded system. 

Process Vrs Thread:

Process is heavy weight where as Thread is light weight. Thread is light weight because process uses it's own address space and thread shares the Process's address space. So Threads are considered to be subset of a process. more over threads consumes less OS resources in terms of physical memory and uses CPU time at most.

Junior programmers think concurrency is hard. 
Experienced programmers think concurrency is easy. 
Senior programmers think concurrency is hard. 
                                                                                  _Java Concurrency Essentials by Martin

                                                                                  

Java supports implementing multi threaded applications using java core API and keywords.
Java Run time in short JRE closely works with native operating system at run time to run applications in multi threaded environment.

Java Support for Thread:

Keywords: synchronized, volatile

API support: Basically Runnable Interface, Thread class, Object class and java.util.concurrency package [> java 5] and few other API

Java categorizes Threads into 2 types.

1. Daemon Threads

Daemon threads mostly runs with less priority to compute some not so important task quickly. periodically. [EX: finalize() of Object class (Not advised to override at all. instead use finally block)] and JVM itself starts few daemon threads internally.
These Threads are active until all normal threads are terminated. The main thread is the last normal thread that gets terminated when the application is closed. Hence once this main thread is terminated all daemon threads are terminated subsequently and application is closed.

NOTE: Any threads can be marked as daemon thread using Thread class setDaemon().

2. User Threads
           
User threads are any threads that programmer creates using java api to compute some tasks concurrently which executes concurrently with other threads.


Advantages of Multi thread Programming:


     Let's consider a use case which demonstrates multi threaded environment.
  1. Simple buffer which stores data temporarily while computing some task.
  2. Buffer size is 10 and dynamically can not be changed.
  3. Producer algorithm: Sequence of instructions which produces data for this buffer.
  4. Consumer algorithm: Sequence of instructions which consumes data from this buffer.
  5. Once buffer is full, delete all elements so that producer algorithm starts producing new feed.
  6. Consumer not allowed to consume data unless buffer is full and empties the buffer
  7. Once it consumes all elements then, let's producer know that it can start producing elements.


This above problem can be considered as a producer and consumer problem which can be solved in number of ways. But it is always good idea to use multiple threads.

How Multi threaded environment enhances the application performance?

Multi threaded programs uses the modern computers operating system resources at maximum, hence gives       
      1. High throughput,
      2. Faster execution,
      3. Quick responsiveness are few among others

Let's see how producer and consumer problem in short PC Problem can be solved using Java:



import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 
 * Buffer implementation with ArrayList and with Producer consumer problem impl
 * using traditional synchronization or implicit lock
 * 
 * @author Nagasharath
 *
 */
public class BufferImpl {

    private CopyOnWriteArrayList<String> buffer;

    private final short SIZE = 10;

    private boolean isBufferFull = false;

    public BufferImpl() {
        buffer = new CopyOnWriteArrayList<String>();
    }

/**
* @throws InterruptedException
*/
private void producesFeed() throws InterruptedException {
    synchronized (this) {

        while (true) {
            if (isBufferFull) {
                System.out.println("Started Consuming!....\n");
                notify();
                wait();
            }

        buffer.add(String.valueOf(System.nanoTime()));
        if (SIZE <= buffer.size()) {
            isBufferFull = true;
            Thread.sleep(10000);
            System.out.println("Buffer full. Production halts...\n");
        }
       }
    }
   }

/**
* @throws InterruptedException
*/
private void consumesFeed() throws InterruptedException {
        synchronized (this) {
            while (true) {
                Iterator<String> iter = buffer.iterator();
                while (iter.hasNext()) {
                    String next = iter.next();
                    System.out.println("Consuming element: " + next);
                    buffer.remove(buffer.indexOf(next));
                }
                isBufferFull = false;
                System.out.println("Started producing!....");
                notify();
                wait();
            }
        }
    }

/**
* @author Nagasharath
*
*/
class ProducerThread extends Thread {
    @Override
    public void run() {
           try {
               producesFeed();
            } catch (InterruptedException e) {

            }
    }
}

/**
* @author Nagasharath
*
*/
class ConsumerThread extends Thread {
     @Override
    public void run() {
        try {
        consumesFeed();
        } catch (InterruptedException e) {

        }
    }
  }

    public static void main(String[] args) {
    BufferImpl impl = new BufferImpl();
    ProducerThread producerThread = impl.new ProducerThread();
    ConsumerThread consumerThread = impl.new ConsumerThread();

    producerThread.start();
    consumerThread.start();
    }
}

Let us simplify the above program

Variables used in the program:

        private CopyOnWriteArrayList<String> buffer;

       private final short SIZE = 10;


        private boolean isBufferFull = false;




buffer is of type CopyOnWriteArrayList [COWA] to store elements. CopyOnWriteArrayList is fail safe data structure which is suitable for concurrent programs. 
Do not forget to run the same program by replacing CopyOnArrayList with ArrayList. If this is the case the program throws ConcurrentModificationException as a result as ArrayList Iterator is fail fast behavior.   


SIZE is a constant of type short which holds the size of COWA data structure

isBufferFull is a switch which holds whether the buffer size is full or not. 


Method to implement Producer algorithm:

 1     /**
 2        * @throws InterruptedException
 3        */
 4     private void producesFeed() throws InterruptedException {
 5         synchronized (this) {
 6
 7             while (true) {
 8                 if (isBufferFull) {
 9                     System.out.println("Started Consuming!....\n");
10                     notify();
11                     wait();
12                 }
13
14             buffer.add(String.valueOf(System.nanoTime()));
15              if (SIZE <= buffer.size()) {
16                 isBufferFull = true;
17                 Thread.sleep(10000);
18                 System.out.println("Buffer full. Production halts...\n");
19             }
20             }
21         }
22     }

producesFeed() uses java keyword synchronized, Object class notify(), Object class wait() and Thread class sleep() to get the job done.

Line 5: keyword synchronized is used to gain the monitor lock on this object. Here this  refers to the    PCProblem object. Lock ensures mutual exclusion. These are of 2 types Implicit locks and reentrent locks. 

synchronized key word is of type implicit lock also known as intrincic lock.

NOTE: Use synchronization judicially because it influences the performance of application. [Slows down the speed of program]   

Let's see more about synchronization and monitor locks in upcoming posts.

Line 7: Initiates the infinite while loop which runs continuously.

Line 10: calls notify() which is one of the inter thread communication Object class api to tell next waiting thread to start it's communication

Line 11: calls wait() which is again one of the inter thread communication Object class api to tell current thread to wait until next running thread notifies.

Line 14: buffer starts holding current time in nano seconds as element of String type. This will be continues till the size reaches 10.
Line 15: checks the above condition

Line 17: Once the SIZE reaches limit to 10 calls Thread.sleep() to make the current running thread to sleep for 10 seconds. [Used here only for demo sake and to simulate the processing behavior]


 1     /**
 2      * @throws InterruptedException
 3      */
 4     private void consumesFeed() throws InterruptedException {
 5         synchronized (this) {
 6             while (true) {
 7                 Iterator<String> iter = buffer.iterator();
 8                 while (iter.hasNext()) {
 9                         String next = iter.next();
10                         System.out.println("Consuming element: " + next);
11                         buffer.remove(buffer.indexOf(next));
12                   }
13                 isBufferFull = false;
14                 System.out.println("Started producing!....");
15                 notify();
16                 wait();
17             }
18         }
19     }

Line 5: Acquires lock on PCProblem Object 

Line 7: Iterator of CopyOnWrireArrayList to iterate over List for processing it. The basic difference between ArrayList and COWA is Fail fast behavior. ArrayList is fail fast and COWA is Fail safe suitable for cuncurrent behavior. 

Note: Never use for (string ele : listObj) { .... } to modify elements in a list. Instead use Iterator.

Line 11: Once element is consumed remove the element from list.

Line 13: Make flag isBufferFull false once all data is consumed.

Line 15 and Line 16: Call to notify() and wait() to tell the producer thread to start it's execution and the latter one to make current thread to wait respectively.

     


 1     /**
 2      * @author Nagasharath
 3      *
 4      */
 5     class ProducerThread extends Thread {
 6         @Override
 7         public void run() {
 8               try {
 9                 producesFeed();
10             } catch (InterruptedException e) {
11
12             }
13         }
14       }
15
16     /**
17      * @author Nagasharath
18      *
19      */
20     class ConsumerThread extends Thread {
21         @Override
22         public void run() {
23             try {
24                 consumesFeed();
25              } catch (InterruptedException e) {
26
27             }
28         }
29       }

The above snippet creates 2 Threads one is Producer thread and the other is Consumer thread. 

Line 1 to Line 16: ProducerThread extends Thead class [part of java core API] then at run time JVM considers closely works with operating system to run this producesFeed() as a separate thread. 

Line 16 to Line 29: ConsumerThread extends Thread class which runs consumerThread() as a seperate thread. In our use case Producer and Consumer executes simultaneously.

 1        public static void main(String[] args) {
 2             BufferImpl impl = new BufferImpl();
 3             ProducerThread producerThread = impl.new ProducerThread();
 4             ConsumerThread consumerThread = impl.new ConsumerThread();
 5
 6             producerThread.start();
 7             consumerThread.start();
 8         }

Line 1: creates main(). Java run time first executes this method as an initial thread. This thread is responsible for creating all other threads. in our case ProducerThread and ConsumerThread.

Line 6 and Line 7: Call to the start() starts producer and consumer threads.

Note: always prefer start() to run() of Thread class to initiate and start new Thread.

 Output:

Buffer full. Production halts...

Started Consuming!....

Consuming element: 2747727445120473
Consuming element: 2747727445291566
Consuming element: 2747727445310340
Consuming element: 2747727445349593
Consuming element: 2747727445369646
Consuming element: 2747727445377753
Consuming element: 2747727445384153
Consuming element: 2747727445390126
Consuming element: 2747727445395673
Consuming element: 2747727445400793
Started producing!....
Buffer full. Production halts...

Started Consuming!....

Consuming element: 2747737453672999
Consuming element: 2747737453761319
Consuming element: 2747737453798013
Consuming element: 2747737453825319
Consuming element: 2747737453849639
Consuming element: 2747737453871826
Consuming element: 2747737453893159
Consuming element: 2747737453914919
Consuming element: 2747737453936679
Consuming element: 2747737453957586
Started producing!....





That's all for now. Next post explains solution to the same PC problem using concurrency utility classes introduced in Java 1.5.

Happy coding! :)

Popular posts

Atomicity with Java Programming Language

 Atomicity with Java What is Atomicity Atomicity, in computer science, is considered to be a property [ALL-OR-NOTHING], that the state of a ...