Monday, September 22, 2014

ReentrantLock Introduction

Lock provides a tool to control access to a shared resource in a multi-threaded environment. A lock provides access to only one thread at a time to the shared resource. Using synchronized methods and statements provides access to an implicit lock for an object. However in certain scenarios we might need access explicitly to the lock object for flexibility. ReentrantLock is a mutual exclusion lock similar to implicit lock provided by synchronized methods and statements but with additional flexibility. 

Java ReentrantLock

Java supports Lock interface in the package java.util.concurrent.locks. ReentrantLock implements the Lock interface and provides the re-entrant mutual exclusive lock. Some of the key APIs of ReentrantLock are listed below.

  • ReentrantLock() - Creates ReentrantLock instance.
  • void lock() - Acquires the lock.
  • void unlock() - Releases the lock.
  • boolean tryLock() - Acquires the lock only if the lock is not held by another thread.
  • boolean isLocked() - Checks if lock is held by another thread.

Java ReentrantLock Example

In this example we have a producer and consumer task using a ReentrantLock object to protect a shared resource. 

package com.sourcetricks.locks;

import java.util.concurrent.locks.ReentrantLock;

public class JavaLocksDemo {

    // Shared resources to be guarded
    private static int count = 0;
    
    // Producer thread. Counts up the resource.
    private static class ProducerTask implements Runnable {

      private ReentrantLock lock = null;
      
      ProducerTask(ReentrantLock lock) {
        this.lock = lock;
      }
      
      @Override
      public void run() {       
          System.out.println("Producer requesting lock");
          lock.lock();
          System.out.println("Producer gets lock");
          for ( int i = 0; i < 5; i++ ) {
            count = count + 1;
            System.out.println("Counting up");
          }
          try {
            Thread.sleep(5000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          System.out.println("Producer releases lock");
          lock.unlock();
      }
      
    }
    
    // Consumer thread. Counts down the resource.
    private static class ConsumerTask implements Runnable {

      private ReentrantLock lock = null;
      
      ConsumerTask(ReentrantLock lock) {
        this.lock = lock;
      }
      
      @Override
      public void run() {
          System.out.println("Consumer requesting lock");
          lock.tryLock();
          System.out.println("Consumer gets lock");
          for ( int i = 0; i < 5; i++ ) {
            count = count - 1;
            System.out.println("Counting down");
          }
          System.out.println("Consumer releases lock");         
          lock.unlock();
      }    
    }
    
  public static void main(String[] args) {
    ReentrantLock lock = new ReentrantLock();
    Thread producer = new Thread(new ProducerTask(lock));
    Thread consumer = new Thread(new ConsumerTask(lock));
    producer.start();
    consumer.start();
  }
}

This program produces the following output.

Producer requesting lock
Consumer requesting lock
Producer gets lock
Counting up
Counting up
Counting up
Counting up
Counting up
Producer releases lock
Consumer gets lock
Counting down
Counting down
Counting down
Counting down
Counting down
Consumer releases lock

Refer to Java Tutorials page for more tutorials.
Sunday, September 14, 2014

Atomic Operations Introduction

Traditional multi-threading approaches use locks to protect shared resources.  Synchronization objects like Semaphores provide mechanisms for the programmer to write code that doesn't modify a shared resource concurrently. The synchronization approaches block other threads when one of the thread is modifying a shared resource. Obviously blocked threads are not doing meaningful work waiting for the lock to be released.

Atomic operations on the contrast are based on non-blocking algorithms in which threads waiting for shared resources don't get postponed. Atomic operations are implemented using hardware primitives like compare and swap (CAS) which are atomic instructions used in multi-threading for synchronization.

Java Atomic Classes

Java supports atomic classes that support lock free, thread safe programming on single variables. These classes are defined in java.util.concurrent.atomic package. Some of the key classes include AtomicBoolean, AtomicInteger, AtomicLong, AtomicIntegerArray, AtomicLongArray and AtomicReference.

Some of the key APIs for AtomicInteger class include:
  • AtomicInteger() - Creates a new AtomicInteger that can be updated atomically. Initial value is set to 0.
  • AtomicInteger(int value) - Creates a new AtomicInteger with the specified initial value.
  • boolean compareAndSet(int expect, int value) - Atomically set the value if the current value is same as expected value.
  • int getAndSet(int newVal) - Atomically sets to new value and returns old value.
  • int getAndIncrement() - Atomically increments the current value and returns old value.
  • int incrementAndGet() - Atomically increments the current value and returns new value.
  • int getAndAdd(int delta) - Atomically adds the delta to current value and returns old value.
Refer to this link for more details.

Java AtomicInteger Example

In this example we have a producer and consumer acting up on a AtomicInteger counter to get lock free synchronization.

package com.sourcetricks.atomic;

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicOpsExample {

  private static AtomicInteger count = new AtomicInteger(0);
  
  // Producer thread. Counts up the resource.
  private static class ProducerTask implements Runnable {

    @Override
      public void run() {
          for ( int i = 0; i < 10; i++ ) {           
            count.getAndIncrement();
            System.out.println("Counting up");   
          }                
      }     
  }

  // Consumer thread. Counts down the resource.
  private static class ConsumerTask implements Runnable {

    @Override
      public void run() {
          for ( int i = 0; i < 3; i++ ) {            
            count.getAndDecrement();
            System.out.println("Counting down");
          }                
      }     
  }
    
  public static void main(String[] args) {
    Thread producer = new Thread(new ProducerTask());
    Thread consumer = new Thread(new ConsumerTask());
    producer.start();
    consumer.start();   
  }
}

This program produces the following output.

Counting up
Counting up
Counting up
Counting up
Counting up
Counting down
Counting down
Counting down
Counting up
Counting up
Counting up
Counting up
Counting up

Refer to this link for more Java Tutorials.

Exchanger Introduction

Exchanger is a synchronization point in which threads can pair and exchange objects. Exchanger simplifies data exchange between two threads. Exchanger waits till two threads reach the synchronization point and then exchanges the data provided by the threads.

Java Exchanger Class

Java support Exchanger synchronization object. Exchanger is a generic class and support the following key APIs.
  • Exchanger() - Constructor to create the exchanger.
  • public V exchange(V x) - Waits for the partner thread to arrive at the exchange point and then swaps the objects

Java Exchanger Example

In this example, we create in the main() program an Exchanger instance for strings. This Exchanger object is then used to exchange strings between the two threads.

package com.sourcetricks.exchanger;

import java.util.concurrent.Exchanger;

public class ExchangerDemo {

  private static class MyTask1 implements Runnable {

    Exchanger<String> exchanger;
    
    MyTask1(Exchanger<String> exchanger) {
      this.exchanger = exchanger;
    }
    
    @Override
    public void run() {
      String str = null;
      try {
        str = exchanger.exchange("Hello from MyTask1");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("Received in MyTask1 = " + str);
    }
    
  }
  
  private static class MyTask2 implements Runnable {

    Exchanger<String> exchanger;
    
    MyTask2(Exchanger<String> exchanger) {
      this.exchanger = exchanger;
    }
    
    @Override
    public void run() {
      String str = null;
      try {
        str = exchanger.exchange("Hello from MyTask2");
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("Received in MyTask2 = " + str);
    }
    
  }
  
  public static void main(String[] args) {
    
    Exchanger<String> exchanger = new Exchanger<String>();
    
    Thread t1 = new Thread(new MyTask1(exchanger));
    Thread t2 = new Thread(new MyTask2(exchanger));
    t1.start();
    t2.start();
  }
}

This program produces the following output.

Received in MyTask2 = Hello from MyTask1
Received in MyTask1 = Hello from MyTask2

Read other concurrency tutorials from Java Tutorials page.
Saturday, September 13, 2014

CyclicBarrier Introduction

CyclicBarrier is a synchronization object that will release when a given number of threads are waiting on it. CyclicBarrier is initialized with a count that indicates the number of threads that must wait on this barrier. CyclicBarrier is useful in applications where threads needs to wait for each other. 

Java CyclicBarrier Class

Java supports CyclicBarrier synchronization object. Some of the key APIs of CyclicBarrier class are listed below.

  • CycliBarrier(int count) - Constructor that creates CyclicBarrier with a specified count. Indicates the number of threads that must invoke await before the barrier is released.
  • int await() - Waits till all threads have invoked wait on this barrier.
  • int await(long timeout, TimeUnit unit) - Waits until all threadshave invoked await on this barrier, or the specified waiting time elapses.

Java CyclicBarrier Example

In this example we have a short task and a long task. We use a CyclicBarrier object to make the short task to wait till the long task has completed. 

package com.sourcetricks.cyclicbarrier;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {

  private static class MyTask1 implements Runnable {
    CyclicBarrier barrier;
    
    MyTask1(CyclicBarrier barrier) {
      this.barrier = barrier;
    }
    
    @Override
    public void run() {
      System.out.println("In MyTask1 ...");
      try {
        Thread.sleep(2000);
        barrier.await();
      } catch (InterruptedException | BrokenBarrierException e) {
        e.printStackTrace();
      }
      System.out.println("Completing MyTask1 ...");
    }
  }
  
  private static class MyTask2 implements Runnable {
    CyclicBarrier barrier;
    
    MyTask2(CyclicBarrier barrier) {
      this.barrier = barrier;
    }
    
    @Override
    public void run() {
      System.out.println("In MyTask2 ...");
      try {
        Thread.sleep(10000);
        barrier.await();
      } catch (InterruptedException | BrokenBarrierException e) {
        e.printStackTrace();
      }
      System.out.println("Completing MyTask2 ...");
    }
  }
  
  public static void main(String[] args) {
    CyclicBarrier barrier = new CyclicBarrier(2);
    Thread t1 = new Thread(new MyTask1(barrier));
    Thread t2 = new Thread(new MyTask2(barrier));
    t1.start();
    t2.start();
  }
}

This program produces the following output.

In MyTask1 ...
In MyTask2 ...
Completing MyTask2 ...
Completing MyTask1 ...

Read other concurrency tutorials from Java Tutorials page.
Tuesday, September 9, 2014

CountDownLatch Introduction

CountDownLatch is a synchronization object that allows a thread to wait till certain events occur in other threads. We can make the current thread to wait until few dependent threads have completed their operation. CountDownLatch starts with a initial count. Thread that needs to wait, blocks until the count reaches to zero. Dependent threads on completing their task start to count down after which all the blocked threads are released.

Java CountDownLatch Class

Java supports CountDownLatch  synchronization object. Some of the key APIs of CountDownLatch class are listed below.
  • CountDownLatch(int count) - Constructor that creates CountDownLatch with a specified count.
  • void await() - Current threads waits till the latch has counted down to zero.
  • boolean await(long timeout, TimeUnit unit) - Causes the current thread to wait till the latch has counted down to zero or the specified timeout has occurred.
  • void countDown() - Decrements the latch count. Releases waiting threads on count reaching zero.

Java CountDownLatch Example

In this example, we create a CountDownLatch object with initial count of two. The main thread creates pre-processing threads and awaits for them to be completed. Once the pre-processing threads complete their tasks they decrement the latch count. Once the latch reaches count of zero then the main thread is released and proceeds to completion.

package cdl;

import java.util.concurrent.CountDownLatch;

public class CDLExample {

  private static class PreProcess1 implements Runnable {

    CountDownLatch cdl = null;
    PreProcess1(CountDownLatch cdl) {
      this.cdl = cdl;
    }
    
    @Override
    public void run() {
      System.out.println("Preprocess1 done");
      cdl.countDown();
    }
  }

  private static class PreProcess2 implements Runnable {

    CountDownLatch cdl = null;
    PreProcess2(CountDownLatch cdl) {
      this.cdl = cdl;
    }
    
    @Override
    public void run() {     
      try {
        Thread.sleep(3000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("Preprocess2 done");
      cdl.countDown();
    }
  }
  
  public static void main(String[] args) {
    CountDownLatch cdl = new CountDownLatch(2);
    try {
      new Thread(new PreProcess1(cdl)).start();
      new Thread(new PreProcess2(cdl)).start();
      System.out.println("Waiting ...");
      cdl.await();
      System.out.println("Completed ...");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

This program produces the following output.

Waiting ...
Preprocess1 done
Preprocess2 done
Completed ...

Read other concurrency tutorials from Java Tutorials page.

Contact Form

Name

Email *

Message *

Back to Top