A lot of people have talked about threading, which is one approach, but consider another way of doing it. What if you had several JVM's started up, connected to the network, and
waiting for work to come their way? How would you program an application
so that it could leverage all of those JVMs without knowing whether or
not they are on the same CPU?
Thread-based Concurrent programming to implement Application Parallelism
- A modern computer has several CPU's or several cores within one CPU. The ability to leverage these multi-cores can be the key for a successful high-volume application.
- Concurrency is the ability to run several programs or several parts of a program in parallel.
- If a time consuming task can be performed asynchronously or in parallel, this improve the throughput and the interactivity of the program.
Multithreading which mean that you could have multiple threads of execution inside the same program. A thread of execution can be thought of as a CPU executing the program. When you have multiple threads executing the same program, it is like having multiple CPU's execute within the same program.
Multithreading and Concurrency in Java
- Java was one of the first languages to make multithreading easily available to developers
- Threading enable developers to write concurrent applications where different threads execute simultaneously
- Threading hazards like deadlock, thread starvation, and race conditions, which result from incorrect use of primitives, are also hard to detect and debug
- Relying on
synchronized
to coordinate access between threads leads to performance issues that affect application scalability, a requirement for many modern applications - The JSR 166: Concurrency Utilities framework was designed to meet the need for a high-level threading facility
Inside the Java Concurrency Utilities
- The Java Concurrency Utilities framework is a library of types that are designed to be used as building blocks for creating concurrent classes or applications
- These types are thread-safe, have been thoroughly tested, and offer high performance
- Types in the Java Concurrency Utilities are organized into small frameworks;
- Executor framework,
- synchronizer,
- concurrent collections,
- locks,
- atomic variables, and
- Fork/Join
- java.util.concurrent contains high-level utility types that are commonly used in concurrent programming
- The java.util.concurrent.atomic subpackage contains low-level utility classes that support lock-free thread-safe programming on single variables.
- The java.util.concurrent.locks sub-package contains low-level utility types for locking and waiting for conditions, which are different from using Java's low-level synchronization and monitors.
The Executor framework
- Because an application creates a new thread for each request, it doesn't scale well when faced with a huge number of requests. For example, each created thread requires memory, and too many threads may exhaust the available memory, forcing the application to terminate
- Rather than always creating a new thread, you could use a thread pool, in which a fixed number of threads would service incoming tasks
- The Executor framework is based on the
Executor
interface - Executor as Object capable of executing
java.lang.Runnable
tasks - Declares the following method for executing a
Runnable
task void execute(Runnable command)
- If the executor cannot execute the task for any reason, this method will
throw a
RejectedExecutionException
- The runnable task is thus able to execute via a new thread, a pooled thread, the calling thread, and so on
ExecutorService
's methods are as- boolean awaitTermination(long timeout, TimeUnit unit) blocks the calling thread until all tasks have completed execution after a shutdown request, the timeout occurs, or the current thread is interrupted, whichever happens first.
- boolean isShutdown() returns true when the executor has been shut down
If, want to use one thread pool with one thread which
executes
several runnables you can use
the
Executors.newSingleThreadExecutor()
method
Threads pools with the Executor Framework
- Thread pools manage a pool of worker threads. The thread pools contains a work queue which holds tasks waiting to get executed.
- A thread pool can be described as a collection of
Runnable
objects (work queue) and a connections of running threads. - These threads are constantly running and are checking the work query for new work.
- If there is new work to be done they execute this Runnable.
- The
Thread
class itself provides a method, e.g. execute(Runnable r) to add
a new
Runnable
object to the work queue. - The ExecutorService adds lifecycle methods to the Executor, which allows to shutdown the Executor and to wait for termination
Java Thread Pool Example using Executors
First we need to have a Runnable class
package com.enoughtheory.threadpool;/** * MyRunnable is the task which will be performed * * @author RaviKantSoni * */public class MyRunnable implements Runnable {
private final long countUntil; MyRunnable(long countUntil) { this.countUntil = countUntil; } @Override public void run() { long sum = 0; for (long i = 1; i < countUntil; i++) { sum += i; } System.out.println(sum); } }
Now you run your Runnable with the executor framework
package com.enoughtheory.threadpool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SimpleThreadPool { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { Runnable worker = new WorkerThread('' + i); executor.execute(worker); } // This will make the executor accept no new threads // and finish all existing threads in the queue
executor.shutdown(); // Wait until all threads are finish executor.awaitTermination(); System.out.println('Finished all threads'); } }