Callable and Future
While Runnable
provides a means to wrap code to be executed in a different thread, it has a limitation in that it cannot return a result from the execution. The only way to get some return value from the execution of a Runnable
is to assign the result to a variable accessible in a scope outside of the Runnable
.
Callable
was introduced in Java 5 as a peer to Runnable
. Callable
is essentially the same except it has a call
method instead of run
. The call
method has the additional capability to return a result and is also allowed to throw checked exceptions.
The result from a Callable task submission is available to be tapped via a Future
Future
can be considered a container of sorts that houses the result of the Callable
computation. Computation of the callable can carry on in another thread, and any attempt to tap the result of a Future
will block and will only return the result once it is available.
Callable Interface
public interface Callable<V> {
V call() throws Exception;
}
Future
Future<V> {
V get()
boolean cancel();
boolean isCancelled();
boolean isDone();
}
Using Callable and Future example:
public static void main(String[] args) throws Exception {
ExecutorService es = Executors.newSingleThreadExecutor();
System.out.println("Time At Task Submission : "+new Date());
Future<String> result = es.submit(new ComplexCalculator());
// the call to Future.get() blocks until the result is available.So we are in for about a 10 sec wait now
System.out.println("Result of Complex Calculation is : "+result.get());
System.out.println("Time At the Point of Printing the Result : "+new Date());
}
Our Callable that does a lengthy computation
public class ComplexCalculator implements Callable<String> {
@Override
public String call() throws Exception {
// just sleep for 10 secs to simulate a lengthy computation
Thread.sleep(10000);
System.out.println( "Result after a lengthy 10sec calculation");
return "Complex Result"; // the result
}
}
Output
Time At Task Submission : Thu Aug 04 15:05:15 EDT 2016
Result after a lengthy 10sec calculation
Result of Complex Calculation is : Complex Result
Time At the Point of Printing the Result : Thu Aug 04 15:05:25 EDT 2016
Other operations permitted on Future
While get() is the method to extract the actual result Future has provision
-
To Cancel the computation by calling
cancel()
-
To Check if computation is complete/finished by calling
isDone()
-
To check if the lengthy task were cancelled
isCancelled()
Execute a task at regular intervals
void scheduleOften() {
final int TEN_SECONDS_IN_MILLIS = 10000;
final int TWO_SECONDS_IN_MILLIS = 2000;
final Timer timer = new Timer(); // final is no longer needed from Java 8 on.
System.out.println("before scheduling:\t" + new Date());
timer.scheduleAtFixedRate(
new TimerTask() {
@Override
public void run() {
System.out.println("inside start:\t" + new Date());
try {
Thread.sleep(TEN_SECONDS_IN_MILLIS);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
System.out.println("inside end:\t" + new Date());
}
},
TEN_SECONDS_IN_MILLIS, // first execution after ten seconds
TWO_SECONDS_IN_MILLIS); // repeat every two seconds
System.out.println("after scheduling:\t" + new Date());
}
Produces output like:
before scheduling: Tue Jan 19 16:17:35 CET 2016
after scheduling: Tue Jan 19 16:17:36 CET 2016
inside start: Tue Jan 19 16:17:46 CET 2016
inside end: Tue Jan 19 16:17:56 CET 2016
inside start: Tue Jan 19 16:17:56 CET 2016
inside end: Tue Jan 19 16:18:06 CET 2016
inside start: Tue Jan 19 16:18:06 CET 2016
The start time of the next execution is calculated by adding the period
to the start time of the current execution. So as long as the task doesn't take longer then period
it gets executed at regular intervals.
It does not run the same Task more then once at any given time, but starts an overdue task right after the current one is finished.
Java Executors provide a simplification for scheduling threads. To schedule a thread to begin execution in the future, a newScheduledThreadPool
can be used, followed by a call to schedule()
.
Runnable runnable = new Runnable() {
public void run() { System.out.println("Hello in the future - " + new Date()); }
}; //create anonymous inner class that implements Runnable
//create a threadpool with 5 available threads
ScheduledExecutorService futurethreads = Executors.newScheduledThreadPool(5);
//Launch the thread at 10 seconds in the future
futurethreads.schedule( runnable, 10, TimeUnit.SECONDS );
System.out.println("Hello from now - " + new Date());
This produces output like
Hello from now - Sat Aug 27 10:47:11 EDT 2016
Hello in the future - Sat Aug 27 10:47:21 EDT 2016
Additionally, to schedule a task for periodic execution, scheduleAtFixedRate()
can be used
Runnable runnable = new Runnable() {
public void run() { System.out.println("Hello in the future - " + new Date()); }
};
long delay = 5; //Begin execution after a delay of 5 seconds
long period = 2; //Schedule execution after the delay and every 2 seconds thereafter
//create a threadpool with 5 available threads
ScheduledExecutorService exec = Executors.newScheduledThreadPool(5);
Future<?> periodicThread = exec.scheduleAtFixedRate(
runnable, delay, period, TimeUnit.SECONDS );
System.out.println("Hello from now - " + new Date());
Produces output like
Hello from now - Sat Aug 27 10:42:39 EDT 2016
Hello in the future - Sat Aug 27 10:42:44 EDT 2016
Hello in the future - Sat Aug 27 10:42:46 EDT 2016
Hello in the future - Sat Aug 27 10:42:48 EDT 2016
Hello in the future - Sat Aug 27 10:42:50 EDT 2016
Hello in the future - Sat Aug 27 10:42:52 EDT 2016
Basic Multithreading
If you have many tasks to execute, and all these tasks are not dependent of the result of the precedent ones, you can use Multithreading for your computer to do all this tasks at the same time using more processors if your computer can. This can make your program execution faster if you have some big independent tasks.
class CountAndPrint implements Runnable {
private final String name;
CountAndPrint(String name) {
this.name = name;
}
/** This is what a CountAndPrint will do */
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println(this.name + ": " + i);
}
}
public static void main(String[] args) {
// Launching 3 parallel threads
for (int i = 1; i <= 3; i++) {
// `start` method will call the `run` method
// of CountAndPrint in another thread
new Thread(new CountAndPrint("Instance " + i)).start();
}
// Doing some others tasks in the main Thread
for (int i = 0; i < 10000; i++) {
System.out.println("main: " + i);
}
}
}
The code of the run method of the various CountAndPrint
instances will execute in non predictable order. A snippet of a sample execution might look like this:
Instance 4: 1
Instance 2: 1
Instance 4: 2
Instance 1: 1
Instance 1: 2
Main: 1
Instance 4: 3
Main: 2
Instance 3: 1
Instance 4: 4
...
CountDownLatch
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
- A CountDownLatch is initialized with a given count.
- The await methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations of await return immediately.
- This is a one-shot phenomenon -- the count cannot be reset. If you need a version that resets the count, consider using a CyclicBarrier.
Key Methods:
public void await()
throws InterruptedException
Causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted.
public void countDown()
Decrements the count of the latch, releasing all waiting threads if the count reaches zero.
Example:
import java.util.concurrent.*;
class DoSomethingInAThread implements Runnable{
CountDownLatch latch;
public DoSomethingInAThread(CountDownLatch latch){
this.latch = latch;
}
public void run() {
try{
System.out.println("Do some thing");
latch.countDown();
}catch(Exception err){
err.printStackTrace();
}
}
}
public class CountDownLatchDemo {
public static void main(String[] args) {
try{
int numberOfThreads = 10;
if (args.length < 1 ){
System.out.println("Usage: java CountDownLatchDemo numberOfThreads");
return;
}
try{
numberOfThreads = Integer.parseInt(args[0]);
}catch(NumberFormatException ne){
}
CountDownLatch latch = new CountDownLatch(numberOfThreads);
for (int n=0; n<numberOfThreads; n++) {
Thread t = new Thread(new DoSomethingInAThread(latch));
t.start();
}
latch.await();
System.out.println("In Main thread after completion of "+numberOfThreads+" threads");
}catch(Exception err){
err.printStackTrace();
}
}
}
output:
java CountDownLatchDemo 5
Do some thing
Do some thing
Do some thing
Do some thing
Do some thing
In Main thread after completion of 5 threads
Explanation:
CountDownLatch
is initialized with a counter of 5 in Main thread- Main thread is waiting by using
await()
method. - Five instances of
DoSomethingInAThread
have been created. Each instance decremented the counter withcountDown()
method. - Once the counter becomes zero, Main thread will resume
Executor framework - newSingleThreadExecutor and newFixedThreadPool
In practice, creating threads manually has multiple drawbacks. In most cases it is unreasonable to create a thread per task or to reinvent the wheel and implement some sort of pooling mechanism manually. Fortunately, the Java SE library contains built-in mechanisms called executors for managing task execution.
There are multiple executors available in the standard library. In this example, we will look at the most basic executors.
-
Executors.newSingleThreadExecutor()
ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i < 5; i++) { final int x = i; executorService.execute(() -> { System.out.println(MessageFormat.format("Task number {0}", x)); }); } System.out.println("Hello world!"); executorService.shutdown();
Output:
Hello world! Task number 0 Task number 1 Task number 2 Task number 3 Task number 4
Tasks scheduled on the SingleThreadExecutor are guaranteed to be executed sequentially. The fact that "Hello world!" appears before "Task number #" makes it apparent that the tasks and the main method aren't executed on the same thread.
-
Executors.newFixedThreadPool(int numberOfThreads)
ExecutorService executorService = Executors.newFixedThreadPool(4); for (int i = 0; i < 5; i++) { final int x = i; executorService.execute(() -> { System.out.println(MessageFormat.format("Task number {0}", x)); }); } System.out.println("Hello world!"); executorService.shutdown();
Output (the order is not deterministic):
Hello world! Task number 2 Task number 3 Task number 0 Task number 1 Task number 4
The FixedThreadPool executes each scheduled task on one of the 4 threads it owns. There are only 4 threads and 5 tasks. Fifth task will wait in the queue until any thread is available. The random order of the printed lines is evidence to the fact that the tasks were executed on different threads.
-
Executors.newCachedThreadPool()
The CachedThreadPool will cache all threads it creates, keeping them active as long as there are tasks to perform or otherwise idle for a given period of time, after which the thread is terminated by the pool, thus saving system resources. Contrary to the fixed-size thread pool, there is no upper limit to the number of threads that a CachedThreadPool can create, which makes it unfit for any controlled usage.
int[] firstArray = { 2, 4, 6, 8 }; int[] secondArray = { 1, 3, 5, 7 }; int[] result = { 0, 0, 0, 0 }; ExecutorService pool = Executors.newCachedThreadPool(); // Setup the ThreadPool: // for each element in the array, submit a worker to the pool that adds elements for (int i = 0; i < result.length; i++) { final int worker = i; pool.submit(() -> result[worker] = firstArray[worker] + secondArray[worker] ); } // Wait for all Workers to finish: try { // execute all submitted tasks pool.shutdown(); // waits until all workers finish, or the timeout ends pool.awaitTermination(12, TimeUnit.SECONDS); } catch (InterruptedException e) { pool.shutdownNow(); //kill thread } System.out.println(Arrays.toString(result));
There is a difference between newFixedThreadPool(1)
and newSingleThreadExecutor()
as the java doc says for the latter:
Unlike the otherwise equivalent newFixedThreadPool(1) the returned executor is guaranteed not to be reconfigurable to use additional threads.
Which means that a newFixedThreadPool
can be reconfigured later in the program by: ((ThreadPoolExecutor) fixedThreadPool).setMaximumPoolSize(10)
This is not possible for newSingleThreadExecutor
Additionally, ExecutorService objects have a invokeAll()
and invokeAny()
methods which allow submission of a list of Callable
objects. The invokeAll()
method will manage the list of jobs until all of them have returned, whereas the invokeAny()
function will return as soon as one of the submitted jobs completes and cancel any jobs that haven't been started yet.
List<Callable<Integer>> jobs = //a list of Callable objects that return an Integer
ExecutorService execService = Executors.newFixedThreadPool(5);
List<Future<Integer>> results = execService.invokeAll( jobs );
//results will be available after all of the jobs have returned
Creating basic deadlocked system .
a deadlock occurs when two competing actions wait for the other to finish, and thus neither ever does . In java there is one lock associated with each object . To avoid concurrent modification done by multiple threads on single object we can use synchronized keyword , but everything comes at a cost . Using synchronized keyword wrongly can lead to stuck systems called as deadlocked system .
Consider there are 2 threads working on 1 instance , Lets call threads as First and Second , and lets say we have 2 resources R1 and R2 . First acquires R1 and also needs R2 for its completion while Second acquires R2 and needs R1 for completion .
so say at time t=0 ,
First has R1 and Second has R2 . now First is waiting for R2 while Second is waiting for R1 . this wait is indefinite and this leads to deadlock .
public class Example2 {
public static void main(String[] args) throws InterruptedException{
final DeadLock dl = new DeadLock();
Thread t1 = new Thread( new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
dl.methodA();
}
});
Thread t2 = new Thread( new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
dl.method2();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t1.setName("First");
t2.setName("Second");
t1.start();
t2.start();
}
}
class DeadLock {
Object mLock1= new Object();
Object mLock2 = new Object();
public void methodA(){
System.out.println("methodA wait for mLock1 " + Thread.currentThread().getName());
synchronized (mLock1) {
System.out.println("methodA mLock1 acquired " + Thread.currentThread().getName());
try {
Thread.sleep(100);
method2();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void method2() throws InterruptedException{
System.out.println("method2 wait for mLock2 " + Thread.currentThread().getName());
synchronized (mLock2) {
System.out.println("method2 mLock2 acquired " + Thread.currentThread().getName());
Thread.sleep(100);
method3();
}
}
public void method3() throws InterruptedException{
System.out.println("method3 mLock1 "+ Thread.currentThread().getName());
synchronized (mLock1) {
System.out.println("method3 mLock1 acquired " + Thread.currentThread().getName());
}
}
}
Output of this program :
methodA wait for mLock1 First
method2 wait for mLock2 Second
method2 mLock2 acquired Second
methodA mLock1 acquired First
method3 mLock1 Second
method2 wait for mLock2 First
Get status of all threads started by your program excluding system threads
Code snippet:
import java.util.Set;
public class ThreadStatus {
public static void main(String args[]) throws Exception{
for ( int i=0; i< 5; i++){
Thread t = new Thread(new MyThread());
t.setName("MyThread:"+i);
t.start();
}
int threadCount = 0;
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for ( Thread t : threadSet){
if ( t.getThreadGroup() == Thread.currentThread().getThreadGroup()){
System.out.println("Thread :"+t+":"+"state:"+t.getState());
++threadCount;
}
}
System.out.println("Thread count started by Main thread:"+threadCount);
}
}
class MyThread implements Runnable{
public void run(){
try{
Thread.sleep(2000);
}catch(Exception err){
err.printStackTrace();
}
}
}
Output:
Thread :Thread[MyThread:1,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:3,5,main]:state:TIMED_WAITING
Thread :Thread[main,5,main]:state:RUNNABLE
Thread :Thread[MyThread:4,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:0,5,main]:state:TIMED_WAITING
Thread :Thread[MyThread:2,5,main]:state:TIMED_WAITING
Thread count started by Main thread:6
Explanation:
Thread.getAllStackTraces().keySet(
) returns all Threads
including application threads + system threads
. If you are interested only in status of Threads, started by your application, iterate the Thread
set by checking Thread Group of a particular thread against your main program thread.
In absence of above ThreadGroup condition, the program returns status of below System Threads:
Reference Handler
Signal Dispatcher
Attach Listener
Finalizer
Locks as Synchronisation aids
Prior to Java 5's concurrent package introduction threading was more low level.The introduction of this package provided several higher level concurrent programming aids/constructs.
Locks are thread synchronisation mechanisms that essentially serve the same purpose as synchronized blocks or key words.
Intrinsic Locking
// int count = 0; // shared among multiple threads
public void doSomething() {
synchronized(this) {
++count;// a non-atomic operation
}
}
Synchronisation using Locks
// int count = 0; // shared among multiple threads
Lock lockObj = new Lock();
public void doSomething() {
try {
lockObj.lock()
++count;// a non-atomic operation
}finally {
lockObj.unlock();// sure to release the lock without fail
}
}
There are several variants of lock available.For more details refer the api docs here
Multiple producer/consumer example with shared global queue
Below code showcases multiple Producer/Consumer program. Both Producer and Consumer threads share same global queue.
import java.util.concurrent.*;
import java.util.Random;
public class ProducerConsumerWithES {
public static void main(String args[]){
BlockingQueue<Integer> sharedQueue = new LinkedBlockingQueue<Integer>();
ExecutorService pes = Executors.newFixedThreadPool(2);
ExecutorService ces = Executors.newFixedThreadPool(2);
pes.submit(new Producer(sharedQueue,1));
pes.submit(new Producer(sharedQueue,2));
ces.submit(new Consumer(sharedQueue,1));
ces.submit(new Consumer(sharedQueue,2));
pes.shutdown();
ces.shutdown();
}
}
/* Different producers produces a stream of integers continuously to a shared queue,
which is shared between all Producers and consumers */
class Producer implements Runnable {
private final BlockingQueue<Integer> sharedQueue;
private int threadNo;
private Random random = new Random();
public Producer(BlockingQueue<Integer> sharedQueue,int threadNo) {
this.threadNo = threadNo;
this.sharedQueue = sharedQueue;
}
@Override
public void run() {
// Producer produces a continuous stream of numbers for every 200 milli seconds
while (true){
try {
int number = random.nextInt(1000);
System.out.println("Produced:" + number + ":by thread:"+ threadNo);
sharedQueue.put(number);
Thread.sleep(200);
} catch (Exception err) {
err.printStackTrace();
}
}
}
}
/* Different consumers consume data from shared queue, which is shared by both producer and consumer threads */
class Consumer implements Runnable{
private final BlockingQueue<Integer> sharedQueue;
private int threadNo;
public Consumer (BlockingQueue<Integer> sharedQueue,int threadNo) {
this.sharedQueue = sharedQueue;
this.threadNo = threadNo;
}
@Override
public void run() {
// Consumer consumes numbers generated from Producer threads continuously
while(true){
try {
int num = sharedQueue.take();
System.out.println("Consumed: "+ num + ":by thread:"+threadNo);
} catch (Exception err) {
err.printStackTrace();
}
}
}
}
output:
Produced:69:by thread:2
Produced:553:by thread:1
Consumed: 69:by thread:1
Consumed: 553:by thread:2
Produced:41:by thread:2
Produced:796:by thread:1
Consumed: 41:by thread:1
Consumed: 796:by thread:2
Produced:728:by thread:2
Consumed: 728:by thread:1
and so on ................
Explanation:
sharedQueue
, which is aLinkedBlockingQueue
is shared among all Producer and Consumer threads.- Producer threads produces one integer for every 200 milli seconds continuously and append it to
sharedQueue
Consumer
thread consumes integer fromsharedQueue
continuously.- This program is implemented with-out explicit
synchronized
orLock
constructs. BlockingQueue is the key to achieve it.
BlockingQueue implementations are designed to be used primarily for producer-consumer queues.
BlockingQueue implementations are thread-safe. All queuing methods achieve their effects atomically using internal locks or other forms of concurrency control.
Producer-Consumer
A simple example of producer-consumer problem solution. Notice that JDK classes (AtomicBoolean
and BlockingQueue
) are used for synchronization, which reduces the chance of creating an invalid solution. Consult Javadoc for various types of BlockingQueue; choosing different implementation may drastically change the behavior of this example (like DelayQueue or Priority Queue).
public class Producer implements Runnable {
private final BlockingQueue<ProducedData> queue;
public Producer(BlockingQueue<ProducedData> queue) {
this.queue = queue;
}
public void run() {
int producedCount = 0;
try {
while (true) {
producedCount++;
//put throws an InterruptedException when the thread is interrupted
queue.put(new ProducedData());
}
} catch (InterruptedException e) {
// the thread has been interrupted: cleanup and exit
producedCount--;
//re-interrupt the thread in case the interrupt flag is needeed higher up
Thread.currentThread().interrupt();
}
System.out.println("Produced "+producedCount+" objects");
}
}
public class Consumer implements Runnable {
private final BlockingQueue<ProducedData> queue;
public Consumer(BlockingQueue<ProducedData> queue) {
this.queue = queue;
}
public void run() {
int consumedCount = 0;
try {
while (true) {
//put throws an InterruptedException when the thread is interrupted
ProducedData data = queue.poll(10, TimeUnit.MILLISECONDS);
// process data
consumedCount++;
}
} catch (InterruptedException e) {
// the thread has been interrupted: cleanup and exit
consumedCount--;
//re-interrupt the thread in case the interrupt flag is needeed higher up
Thread.currentThread().interrupt();
}
System.out.println("Consumed "+consumedCount+" objects");
}
}
public class ProducerConsumerExample {
static class ProducedData {
// empty data object
}
public static void main(String[] args) throws InterruptedException {
BlockingQueue<ProducedData> queue = new ArrayBlockingQueue<ProducedData>(1000);
// choice of queue determines the actual behavior: see various BlockingQueue implementations
Thread producer = new Thread(new Producer(queue));
Thread consumer = new Thread(new Consumer(queue));
producer.start();
consumer.start();
Thread.sleep(1000);
producer.interrupt();
Thread.sleep(10);
consumer.interrupt();
}
}
Synchronized methods
Beside synchronized
blocks, there are also synchronized
methods.
The following blocks of code are practically equivalent (even though the bytecode seems to be different):
-
synchronized
block onthis
:public void foo(){ synchronized(this){ doStuff(); } }
-
synchronized
method:public synchronized void foo(){ doStuff(); }
Likewise for static
methods, this:
class MyClass {
...
public static void bar() {
synchronized(MyClass.class) {
doSomeOtherStuff();
}
}
}
has the same effect as this:
class MyClass {
...
public static synchronized void bar() {
doSomeOtherStuff();
}
}
The Runnable Interface
The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread. The class must define a method of no arguments called run.
The Runnable
interface defines a single method, run()
, meant to contain the code executed in the thread. The Runnable
object is passed to the Thread
constructor. And Thread's start()
method is called.
Runnable vs Thread subclass
A Runnable
object employment is more general, because the Runnable
object can subclass a class other than Thread
.
Thread
subclassing is easier to use in simple applications, but is limited by the fact that your task class must be a descendant of Thread
.
A Runnable
object is applicable to the high-level thread management APIs.
Example
public void run() {
System.out.println("Hello from a thread!1");
System.out.println("Hello from a thread!2");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Hello from a thread!3");
System.out.println("Hello from a thread!4");
}
public static void main(String args[]) throws InterruptedException {
Thread helloWorld = new Thread(new HelloWorldRunnable());
helloWorld.start();
System.out.println("Hello from the main -thread!1");
System.out.println("Hello from the main -thread!2");
Thread.sleep(5);
System.out.println("Hello from the main -thread!3");
System.out.println("Hello from the main -thread!4");
}
Output:
Hello from the main -thread!1
Hello from the main -thread!2
Hello from a thread!1
Hello from a thread!2
Hello from the main -thread!3
Hello from the main -thread!4
Hello from a thread!3
Hello from a thread!4
Example in Java8:
public static void main(String[] args) {
Runnable r = () -> System.out.println("Hello world");
new Thread(r).start();
}
This interface is designed to provide a common protocol for objects that wish to execute code while they are active. For example, Runnable is implemented by class Thread. Being active simply means that a thread has been started and has not yet been stopped. The statements will be excuted paralell to your main thread.
When the thread is started the run()-method is executed. After finishing executing all statements in the run method the thread will be stopped.
Thread.sleep(x); puts the thread on pause for x milliseconds.
Using ThreadLocal
A useful tool in Java Concurrency is ThreadLocal - this allows you to have a variable that will be unique to a given thread. For example, you may be working in a servlet and want to have access to the requester's context. You might do something like this
private static final ThreadLocal<MyUserContext> contexts = new ThreadLocal<>();
public static MyUserContext getContext() {
return contexts.get(); // get returns the variable unique to this thread
}
public void doGet(...) {
MyUserContext context = magicGetContextFromRequest(request);
contexts.put(context); // save that context to our thread-local - other threads
// making this call don't overwrite ours
try {
// business logic
} finally {
contexts.remove(); // 'ensure' removal of thread-local variable
}
}
Now, instead of passing MyUserContext
into every single method, you can simply use MyServlet.getContext()
where you need it. Now of course, this does introduce a variable that needs to be documented, but it's thread safe (unless you kick off other threads with your Servlet) which eliminates a lot of the downsides to using such a highly scoped variable.
The key advantage here is that every thread has its own thread local variable in that contexts
container. As long as you use it from a defined entry point (like demanding that each servlet maintains its context, or perhaps by adding a servlet filter) you can rely on this context being there when you need it. Obviously this simple example can be expanded upon in production code.
Add two `int` arrays using a Threadpool
A Threadpool has a Queue of tasks, of which each will be executed on one these Threads.
The following example shows how to add two int
arrays using a Threadpool.
int[] firstArray = { 2, 4, 6, 8 };
int[] secondArray = { 1, 3, 5, 7 };
int[] result = { 0, 0, 0, 0 };
ExecutorService pool = Executors.newCachedThreadPool();
// Setup the ThreadPool:
// for each element in the array, submit a worker to the pool that adds elements
for (int i = 0; i < result.length; i++) {
final int worker = i;
pool.submit(() -> result[worker] = firstArray[worker] + secondArray[worker] );
}
// Wait for all Workers to finish:
try {
// execute all submitted tasks
pool.shutdown();
// waits until all workers finish, or the timeout ends
pool.awaitTermination(12, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
pool.shutdownNow(); //kill thread
}
System.out.println(Arrays.toString(result));
Notes:
-
This example is purely illustrative. In practice, there won't be any speedup by using threads for a task this small. A slowdown is likely, since the overheads of task creation and scheduling will swamp the time taken to run a task.
-
If you were using Java 7 and earlier, you would use anonymous classes instead of lambdas to implement the tasks.
Atomic operations
An atomic operation is an operation that is executed "all at once", without any chance of other threads observing or modifying state during the atomic operation's execution.
Lets consider a BAD EXAMPLE.
private static int t = 0;
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(400); // The high thread count is for demonstration purposes.
for (int i = 0; i < 100; i++) {
executorService.execute(() -> {
t++;
System.out.println(MessageFormat.format("t: {0}", t));
});
}
executorService.shutdown();
}
In this case, there are two issues. The first issue is that the post increment operator is not atomic. It is comprised of multiple operations: get the value, add 1 to the value, set the value. That's why if we run the example, it is likely that we won't see t: 100
in the output - two threads may concurrently get the value, increment it, and set it: let's say the value of t is 10, and two threads are incrementing t. Both threads will set the value of t to 11, since the second thread observes the value of t before the first thread had finished incrementing it.
The second issue is with how we are observing t. When we are printing the value of t, the value may have already been changed by a different thread after this thread's increment operation.
To fix those issues, we'll use the java.util.concurrent.atomic.AtomicInteger
,
which has many atomic operations for us to use.
private static AtomicInteger t = new AtomicInteger(0);
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(400); // The high thread count is for demonstration purposes.
for (int i = 0; i < 100; i++) {
executorService.execute(() -> {
int currentT = t.incrementAndGet();
System.out.println(MessageFormat.format("t: {0}", currentT));
});
}
executorService.shutdown();
}
The incrementAndGet
method of AtomicInteger
atomically increments and returns the new value, thus eliminating the previous race condition. Please note that in this example the lines will still be out of order because we make no effort to sequence the println
calls and that this falls outside the scope of this example, since it would require synchronization and the goal of this example is to show how to use AtomicInteger
to eliminate race conditions concerning state.
Create and Resolve deadlock in java
public class Deadlock {
public static void main(String[] args) {
final String s1 = "Hello";
final String s2 = "Hi";
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (s2) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s1) {
System.out.println(s1 + s2);
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (s2) {
synchronized (s1) {
System.out.println(s1 + s2);
}
}
}
});
t1.start();
t2.start();
}
}
Here the first thread t1 acquires a lock on s2 and is waiting for a lock on s1 which is held by thread t2. But t2 is itself waiting for t1 to release lock on s2. So these are in deadlock.
Output : program will never exit
The Thread.sleep ensures that they are in deadlock otherwise it might just happen that the thread executes so quickly that the deadlock never happens.
Solution : Reverse the order of locking in either of the threads (not both at once). eg changed order for thread t1
public void run() {
synchronized (s1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (s2) {
System.out.println(s1 + s2);
}
}
}
Now that they will acquire lock in the same order. One thread will execute : s1 then s2 followed by the other
Output : HelloHi HelloHi
Creating a java.lang.Thread instance
There are two main approaches to creating a thread in Java. In essence, creating a thread is as easy as writing the code that will be executed in it. The two approaches differ in where you define that code.
In Java, a thread is represented by an object - an instance of java.lang.Thread or its subclass. So the first approach is to create that subclass and override the run() method.
Note: I'll use Thread to refer to the java.lang.Thread class and thread to refer to the logical concept of threads.
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Thread running!");
}
}
}
Now since we've already defined the code to be executed, the thread can be created simply as:
MyThread t = new MyThread();
The Thread class also contains a constructor accepting a string, which will be used as the thread's name. This can be particulary useful when debugging a multi thread program.
class MyThread extends Thread {
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Thread running! ");
}
}
}
MyThread t = new MyThread("Greeting Producer");
The second approach is to define the code using java.lang.Runnable and its only method run(). The Thread class then allows you to execute that method in a separated thread. To achieve this, create the thread using a constructor accepting an instance of the Runnable interface.
Thread t = new Thread(aRunnable);
This can be very powerful when combined with lambdas or methods references (Java 8 only):
Thread t = new Thread(operator::hardWork);
You can specify the thread's name, too.
Thread t = new Thread(operator::hardWork, "Pi operator");
Practicaly speaking, you can use both approaches without worries. However the general wisdom says to use the latter.
For every of the four mentioned constructors, there is also an alternative accepting an instance of java.lang.ThreadGroup as the first parameter.
ThreadGroup tg = new ThreadGroup("Operators");
Thread t = new Thread(tg, operator::hardWork, "PI operator");
The ThreadGroup represents a set of threads. You can only add a Thread to a ThreadGroup using a Thread's constructor. The ThreadGroup can then be used to manage all its Threads together, as well as the Thread can gain information from its ThreadGroup.
So to sumarize, the Thread can be created with one of these public constructors:
Thread()
Thread(String name)
Thread(Runnable target)
Thread(Runnable target, String name)
Thread(ThreadGroup group, String name)
Thread(ThreadGroup group, Runnable target)
Thread(ThreadGroup group, Runnable target, String name)
Thread(ThreadGroup group, Runnable target, String name, long stackSize)
The last one allows us to define desired stack size for the new thread.
Often the code readability suffers when creating and configuring many Threads with same properties or from the same pattern. That's when java.util.concurrent.ThreadFactory can be used. This interface allows you to encapsulate the procedure of creating the thread through the factory pattern and its only method newThread(Runnable).
class WorkerFactory implements ThreadFactory {
private int id = 0;
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "Worker " + id++);
}
}
Excecute Methods with Thread in parallel
public class SimpleThread {
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
show_messages();
}
};
thread.start();
System.out.println("I start the Thread and i finished my job");
}
private static void show_messages() {
for (int i = 0; i < 10; i++) {
try {
System.out.println("Hello, i'm THREAD");
Thread.sleep(1000);
} catch (Exception e) {
System.out.println("Exception = " + e);
}
}
}
}
Result
I start the Thread and i finished my job
Hello, i'm THREAD
Hello, i'm THREAD
Hello, i'm THREAD
Hello, i'm THREAD
Hello, i'm THREAD
Hello, i'm THREAD
Hello, i'm THREAD
Hello, i'm THREAD
Hello, i'm THREAD
Hello, i'm THREAD
Exclusive write / Concurrent read access
It is sometimes required for a process to concurrently write and read the same "data".
The ReadWriteLock
interface, and its ReentrantReadWriteLock
implementation allows for an access pattern that can be described as follow :
- There can be any number of concurrent readers of the data. If there is at least one reader access granted, then no writer access is possible.
- There can be at most one single writer to the data. If there is a writer access granted, then no reader can access the data.
An implementation could look like :
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Sample {
// Our lock. The constructor allows a "fairness" setting, which guarantees the chronology of lock attributions.
protected static final ReadWriteLock RW_LOCK = new ReentrantReadWriteLock();
// This is a typical data that needs to be protected for concurrent access
protected static int data = 0;
/** This will write to the data, in an exclusive access */
public static void writeToData() {
RW_LOCK.writeLock().lock();
try {
data++;
} finally {
RW_LOCK.writeLock().unlock();
}
}
public static int readData() {
RW_LOCK.readLock().lock();
try {
return data;
} finally {
RW_LOCK.readLock().unlock();
}
}
}
Note 1 : This precise use case has a cleaner the solution using AtomicInteger
, but what is described here is an access pattern, that works regardless of the fact that data here is an integer that as an Atomic variant.
NOTE 2 : the lock on the reading part really is needed, although it might not look so to the casual reader. Indeed, if you do not lock on the reader side, any number of things can go wrong, amongst which :
- The writes of primitive values are not guaranteed to be atomic on all JVMs, so the reader could see e.g. only 32bits of a 64bits write if
data
were a 64bits long type - The visibility of the write from a thread that did not perform it is guaranteed by the JVM only if we establish an Happen Before relationship between the writes and the reads. This relationship is established when both readers and writers use their respective locks, but not otherwise
In case higher performance is required, an under certain types of usage, there is a faster lock type available, called the StampedLock
, that amongst other things implements an optimistic lock mode. This lock works very differently from the ReadWriteLock
, and this sample is not transposable.
Intrinsic locking
In Java, there is a built-in language-level locking mechanism: the synchronized
block, which can use any Java object as an intrinsic lock (i.e. every Java object may have a monitor associated with it).
Intrinsic locks provide atomicity to groups of statements. To understand what that means for us, let's have a look at an example where synchronized
is useful:
private static int t = 0;
private static Object mutex = new Object();
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(400); // The high thread count is for demonstration purposes.
for (int i = 0; i < 100; i++) {
executorService.execute(() -> {
synchronized (mutex) {
t++;
System.out.println(MessageFormat.format("t: {0}", t));
}
});
}
executorService.shutdown();
}
In this case, if it weren't for the synchronized
block, there would have been multiple concurrency issues involved. The first one would be with the post increment operator (it isn't atomic in itself), and the second would be that we would be observing the value of t after an arbitrary amount of other threads has had the chance to modify it. However, since we acquired an intrinsic lock, there will be no race conditions here and the output will contain numbers from 1 to 100 in their normal order.
Intrinsic locks in Java are mutexes (i.e. mutual execution locks). Mutual execution means that if one thread has acquired the lock, the second will be forced to wait for the first one to release it before it can acquire the lock for itself. Note: An operation that may put the thread into the wait (sleep) state is called a blocking operation. Thus, acquiring a lock is a blocking operation.
Pausing Execution
Thread.sleep
causes the current thread to suspend execution for a specified period. This is an efficient means of making processor time available to the other threads of an application or other applications that might be running on a computer system. There are two overloaded sleep
methods in the Thread class.
One that specifies the sleep time to the millisecond
public static void sleep(long millis) throws InterruptedException
One that specifies the sleep time to the nanosecond
public static void sleep(long millis, int nanos)
Pausing Execution for 1 second
Thread.sleep(1000);
It is important to note that this is a hint to the operating system's kernel's scheduler. This may not necessarily be precise, and some implementations do not even consider the nanosecond parameter (possibly rounding to the nearest millisecond).
It is recommended to enclose a call to Thread.sleep
in try/catch and catch InterruptedException
.
Reentrancy of intrinsic locks
Intrinsic locks in Java are reentrant. This means that if a thread attempts to acquire a lock it already owns, it will not block and it will successfully acquire it. For instance, the following code will not block when called:
public void bar(){
synchronized(this){
...
}
}
public void foo(){
synchronized(this){
bar();
}
}
Runnable Object
The Runnable
interface defines a single method, run()
, meant to contain the code executed in the thread.
The Runnable
object is passed to the Thread
constructor. And Thread's start()
method is called.
Example
public class HelloRunnable implements Runnable {
@Override
public void run() {
System.out.println("Hello from a thread");
}
public static void main(String[] args) {
new Thread(new HelloRunnable()).start();
}
}
Example in Java8:
public static void main(String[] args) {
Runnable r = () -> System.out.println("Hello world");
new Thread(r).start();
}
Runnable vs Thread subclass
A Runnable
object employment is more general, because the Runnable
object can subclass a class other than Thread
.
Thread
subclassing is easier to use in simple applications, but is limited by the fact that your task class must be a descendant of Thread
.
A Runnable
object is applicable to the high-level thread management APIs.
Semaphore
Basically, a Semaphore is a counter, that restricts the number of threads that can get access to a critical section. Semaphore maintains a set of permits. Which are acquires when access is granted to the critical section and are released when the critical section exists.
A semaphore is initialized as:
Semaphore semaphore = new Semaphore(1); //the int value being the number of permits
The Semaphore constructor accepts an additional boolean parameter for fairness, when set false, this class makes no guarantees about the order in which threads acquire permits. When fairness is set true, the semaphore guarantees that threads invoking any of the acquire methods are selected to obtain permits in the order in which their invocation of those methods was processed. It is declared in the following manner:
Semaphore semaphore = new Semaphore(1, true);
Now let's look at an example from javadocs, where Semaphore is used to control access to a pool of items:
class Pool {
private static final int MAX_AVAILABLE = 100;
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
public Object getItem() throws InterruptedException {
available.acquire();
return getNextAvailableItem();
}
public void putItem(Object x) {
if (markAsUnused(x))
available.release();
}
private Object getNextAvailableItem(){
//implementation
}
private void markAsUnused(Object o){
//implementation
}
}
The Event Dispatch Thread
When using a Swing GUI, all event-handling code that deals with Swing objects should run on a special thread known as the Event Dispatch Thread (EDT). This is necessary because the methods in Swing objects are sometimes not thread-safe: invoking them from multiple threads risks thread interference or memory consistency errors.
Thus, changes to Swing GUI elements (like calling setBackground
on a Window) should generally be processed on the Event Dispatch Thread. If your GUI change is happening within a GUI-activated event, then the code will run on the Event Dispatch Thread.
If you'd like to make changes to a Swing GUI element from a Thread that is not the Event Dispatch Thread, you can invoke the Event Dispatch Thread with a call like this:
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
//Your GUI code here
}
});
}
If you want your current Thread to wait for a Swing GUI change, you may wish to use invokeAndWait
instead of invokeLater
.
It's useful to think of the code running on the Event Dispatch Thread as a series of short tasks. Most tasks are invocations of event-handling methods activated from the GUI, such as ActionListener.actionPerformed
. These are processed by the Event Dispatch Thread automatically. Tasks on the Event Dispatch Thread must finish quickly; if they don't, unhandled events back up and the user interface becomes unresponsive.
Because of this, it's important that computation-heavy tasks are not given to the Event Dispatch Thread. Note that invokeLater
and invokeAndWait
should generally only be used for lightweight GUI-related changes.
Determine whether your code is running on the event dispatch thread using:
javax.swing.SwingUtilities.isEventDispatchThread
Thread with pause/resume functionality
This snippet is to simply hold the Thread when you don't need it for a period of time and then to resume it later on.
private volatile boolean runningFlag = false;
private volatile boolean killThread = false;
private Thread refreshThread;
refreshThread = new Thread(new Runnable() {
@Override
public void run() {
while (!killThread) {
try {
synchronized (refreshThread) {
while (!runningFlag) refreshThread.wait();
}
// do stuff e.g. refresh a RSS feed or smth.
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
refreshThread.start();
public void pauseAutoRefresh() {
runningFlag = false;
}
public void resumeAutoRefresh() {
runningFlag = true;
synchronized (refreshThread) {
refreshThread.notify();
}
public void killThread(){
killThread = true;
refreshThread.interrupt();
}
Visibility with synchronized / volatile
As we know that we should use synchronized
keyword to make execution of a method or block exclusive. But few of us may not be aware of one more important aspect of using synchronized
and volatile
keyword: apart from making a unit of code atomic, it also provides read / write barrier. What is this read / write barrier? Let's discuss this using an example:
class Counter {
private Integer count = 10;
public synchronized void incrementCount() {
count++;
}
public Integer getCount() {
return count;
}
}
Let's suppose a thread A calls incrementCount()
first then another thread B calls getCount()
. In this scenario there is no guarantee that B will see updated value of count
. It may still see count
as 10
, even it is also possible that it never sees updated value of count
ever.
To understand this behavior we need to understand how Java memory model integrates with hardware architecture. In Java, each thread has it's own thread stack. This stack contains: method call stack and local variable created in that thread. In a multi core system, it is quiet possible that two threads are running concurrently in separate cores. In such scenario it is possible that part of a thread's stack lies inside register / cache of a core. If inside a thread, an object is accessed using synchronized
(or volatile
) keyword, after synchronized
block that thread syncs it's local copy of that variable with the main memory. This creates a read / write barrier and makes sure that the thread is seeing the latest value of that object.
But in our case, since thread B has not used synchronized access to count
, it might be refering value of count
stored in register and may never see updates from thread A. To make sure that B sees latest value of count we need to make getCount()
synchronized as well.
public synchronized Integer getCount() {
return count;
}
Now when thread A is done with updating count
it unlocks Counter
instance, at the same time creates write barrier and flushes all changes done inside that block to the main memory. Similarly when thread B acquires lock on the same instance of Counter
, it enters into read barrier and reads value of count
from main memory and sees all updates.
Same visibility effect goes for volatile
read / writes as well. All variables updated prior to write to volatile
will be flushed to main memory and all reads after volatile
variable read will be from main memory.
Sign up or log in
Save edit as a guest
Join Stack Overflow
We recognize you from another Stack Exchange Network site!
Join and Save Draft