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.
Java Run time in short JRE closely works with native operating system at run time to run applications in multi threaded environment.
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.
- Simple buffer which stores data temporarily while computing some task.
- Buffer size is 10 and dynamically can not be changed.
- Producer algorithm: Sequence of instructions which produces data for this buffer.
- Consumer algorithm: Sequence of instructions which consumes data from this buffer.
- Once buffer is full, delete all elements so that producer algorithm starts producing new feed.
- Consumer not allowed to consume data unless buffer is full and empties the buffer
- 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?
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:
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.
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 }
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.
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 }
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 }
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! :)