Multithreading
Multithreading
1) It doesn't block the user because threads are independent and you can perform multiple
operations at the same time.
3) Threads are independent, so it doesn't affect other threads if an exception occurs in a single
thread.
Multitasking
Multitasking is a process of executing multiple tasks simultaneously. We use multitasking to
utilize the CPU. Multitasking can be achieved in two ways:
o Each process has an address in memory. In other words, each process allocates a separate
memory area.
o A process is heavyweight.
o Cost of communication between the process is high.
o Switching from one process to another requires some time for saving and loading
registers, memory maps, updating lists, etc.
Thread class:
Thread class provide constructors and methods to create and perform operations on a
thread. Thread class extends Object class and implements Runnable interface.
Thread()
Thread(String name)
Thread(Runnable r)
Thread(Runnable r,String name)
Runnable interface:
The Runnable interface should be implemented by any class whose instances are intended to be
executed by a thread. Runnable interface have only one method named run().
public void run(): is used to perform action for a thread.
Starting a thread:
start() method of Thread class is used to start a newly created thread. It performs following tasks:
A new thread starts(with new callstack).
The thread moves from New state to the Runnable state.
When the thread gets a chance to execute, its target run() method will run.
If you are not extending the Thread class,your class object would not be treated as a thread
object.So you need to explicitely create Thread class object.
We are passing the object of your class that implements Runnable so that your class run()
method may execute.
There is no guarantee that which runnable thread will be chosen to run by the thread
scheduler.
Only one thread at a time can run in a single process.
The thread scheduler mainly uses preemptive or time slicing scheduling to schedule the
threads.
1
1
2
2
3
3
4
4
As you know well that at a time only one thread is executed. If you sleep a thread for the
specified time,the thread shedular picks up another thread and so on.
t1.run();
t2.run();
}
}
Output:1
2
3
4
5
1
2
3
4
5
As you can see in the above program that there is no context-switching because here t1 and t2
will be treated as normal object not thread object.
IsAlive and Join Methods(Very Important)
Sometimes one thread needs to know when other thread is terminated or not. In java,
isAlive() and join() are two different methods that are used to check whether a thread has
finished its execution or not.
The isAlive() method returns true if the thread upon which it is called is still running
otherwise it returns false.
But, join() method is used more commonly than isAlive(). This method waits until the
thread on which it is called terminates.
There are overloaded versions of join() method, which allows us to specify time for
which you want to wait for the specified thread to terminate.
final void join(long milliseconds) throws InterruptedException
As we have seen in the introduction to MultiThreading, the main thread must always be
the last thread to finish its execution. Therefore, we can use Thread join() method to
ensure that all the threads created by the program has been terminated before the
termination of the main thread.
r1
true
true
r1
r2
r2
r1
r1
r2
r2
In this above program two thread t1 and t2 are created. t1 starts first and after printing "r1" on console
thread t1 goes to sleep for 500 ms. At the same time Thread t2 will start its process and print "r1" on
console and then go into sleep for 500 ms. Thread t1 will wake up from sleep and print "r2" on console
similarly thread t2 will wake up from sleep and print "r2" on console. So you will get output like r1 r1 r2
r2
try{
t1.join(); //Waiting for t1 to finish
}catch(InterruptedException ie){}
t2.start();
}
}
Output :
r1
r2
r1
r2
In this above program join() method on thread t1 ensures that t1 finishes it process before thread t2
starts.
Specifying time with join()
If in the above program, we specify time while using join() with t1, then t1 will execute for that time, and
then t2 will join it.
t1.join(1500);
Doing so, initially t1 will execute for 1.5 seconds, after which t2 will join it.
Naming Thread
The Thread class provides methods to change and get the name of a thread. By default, each
thread has a name i.e. thread-0, thread-1 and so on. By we can change the name of the thread by
using setName() method. The syntax of setName() and getName() methods are given below:
Output:
Name of t1:Thread-0
Name of t2:Thread-1
id of t1:8
running...
After changeling name of t1:Sonoo Jaiswal
running...
Current Thread
1. class TestMultiNaming2 extends Thread{
2. public void run(){
3. System.out.println(Thread.currentThread().getName());
4. }
5. public static void main(String args[]){
6. TestMultiNaming2 t1=new TestMultiNaming2();
7. TestMultiNaming2 t2=new TestMultiNaming2();
8.
9. t1.start();
10. t2.start();
11. }
12. }
Output:Thread-0
Thread-1
Priority of a Thread (Thread Priority):
Each thread have a priority.
Priorities are represented by a number between 1 and 10.
In most cases, thread scheduler schedules the threads according to their priority (known
as preemptive scheduling).
But it is not guaranteed because it depends on JVM specification that which scheduling it
chooses.
3 constants defined in Thread class:
public static int MIN_PRIORITY
public static int NORM_PRIORITY
public static int MAX_PRIORITY
Default priority of a thread is 5 (NORM_PRIORITY). The value of MIN_PRIORITY is 1 and
the value of MAX_PRIORITY is 10.
}
public static void main(String args[]){
TestMultiPriority1 m1=new TestMultiPriority1();
TestMultiPriority1 m2=new TestMultiPriority1();
m1.setPriority(Thread.MIN_PRIORITY);
m2.setPriority(Thread.MAX_PRIORITY);
m1.start();
m2.start();
}
}
Output:
running thread name is:Thread-0
running thread priority is:10
running thread name is:Thread-1
running thread priority is:1
Daemon Thread in Java
Daemon thread in java is a service provider thread that provides services to the user
thread. Its life depend on the mercy of user threads i.e. when all the user threads dies,
JVM terminates this thread automatically.
There are many java daemon threads running automatically e.g. gc, finalizer etc.
You can see all the detail by typing the jconsole in the command prompt. The jconsole
tool provides information about the loaded classes, memory usage, running threads etc.
t1.start();//starting threads
t2.start();
t3.start();
}
}
Output
daemon thread work
user thread work
user thread work
Note: If you want to make a user thread as Daemon, it must not be started otherwise it will
throw IllegalThreadStateException.
class TestMultitasking3{
public static void main(String args[]){
Simple1 t1=new Simple1();
Simple2 t2=new Simple2();
t1.start();
t2.start();
}
}
Output:
task one
task two
Synchronization in Java
When two or more threads need access to a shared resource, they need some way to
ensure that the resource will be used by only one thread at a time. The process by which
this is achieved is called synchronization.
Synchronization in java is the capability to control the access of multiple threads to any
shared resource.
Java Synchronization is better option where we want to allow only one thread to access
the shared resource.
Why use Synchronization
There are two types of thread synchronization mutual exclusive and inter-thread communication.
1. Mutual Exclusive
1. Synchronized method.
2. Synchronized block.
3. static synchronization.
2. Cooperation (Inter-thread communication in java)
Mutual Exclusive
Mutual Exclusive helps keep threads from interfering with one another while sharing data. This
can be done by three ways in java:
1. by synchronized method
2. by synchronized block
3. by static synchronization
Synchronization is built around an internal entity known as the lock or monitor. Every object has
an lock associated with it. By convention, a thread that needs consistent access to an object's
fields has to acquire the object's lock before accessing them, and then release the lock when it's
done with them.
//example of java synchronized method
1. class Table{
2. synchronized void printTable(int n){//synchronized method
3. for(int i=1;i<=5;i++){
4. System.out.println(n*i);
5. try{
6. Thread.sleep(400);
7. }catch(Exception e){System.out.println(e);}
8. }
9.
10. }
11. }
12.
13. class MyThread1 extends Thread{
14. Table t;
15. MyThread1(Table t){
16. this.t=t;
17. }
18. public void run(){
19. t.printTable(5);
20. }
21.
22. }
23. class MyThread2 extends Thread{
24. Table t;
25. MyThread2(Table t){
26. this.t=t;
27. }
28. public void run(){
29. t.printTable(100);
30. }
31. }
32.
33. public class TestSynchronization2{
34. public static void main(String args[]){
35. Table obj = new Table();//only one object
36. MyThread1 t1=new MyThread1(obj);
37. MyThread2 t2=new MyThread2(obj);
38. t1.start();
39. t2.start();
40. }
41. }
class Table{
o
o void printTable(int n){
o synchronized(this){//synchronized block
o for(int i=1;i<=5;i++){
o System.out.println(n*i);
o try{
o Thread.sleep(400);
o }catch(Exception e){System.out.println(e);}
o }
o }
o }//end of the method
o }
o
o class MyThread1 extends Thread{
o Table t;
o MyThread1(Table t){
o this.t=t;
o }
o public void run(){
o t.printTable(5);
o }
o
o }
o class MyThread2 extends Thread{
o Table t;
o MyThread2(Table t){
o this.t=t;
o }
o public void run(){
o t.printTable(100);
o }
o }
o
o public class TestSynchronizedBlock1{
o public static void main(String args[]){
o Table obj = new Table();//only one object
o MyThread1 t1=new MyThread1(obj);
o MyThread2 t2=new MyThread2(obj);
o t1.start();
o t2.start();
o }
o }
Static synchronization
If you make any static method as synchronized, the lock will be on the class not on object.
Suppose there are two objects of a shared class(e.g. Table) named object1 and object2.In case of
synchronized method and synchronized block there cannot be interference between t1 and t2 or
t3 and t4 because t1 and t2 both refers to a common object that have a single lock.But there can
be interference between t1 and t3 or t2 and t4 because t1 acquires another lock and t3 acquires
another lock.I want no interference between t1 and t3 or t2 and t4.Static synchronization solves
this problem.
1. class Table{
2.
3. synchronized static void printTable(int n){
4. for(int i=1;i<=10;i++){
5. System.out.println(n*i);
6. try{
7. Thread.sleep(400);
8. }catch(Exception e){}
9. }
10. }
11. }
12.
13. class MyThread1 extends Thread{
14. public void run(){
15. Table.printTable(1);
16. }
17. }
18.
19. class MyThread2 extends Thread{
20. public void run(){
21. Table.printTable(10);
22. }
23. }
24.
25. class MyThread3 extends Thread{
26. public void run(){
27. Table.printTable(100);
28. }
29. }
30. class MyThread4 extends Thread{
31. public void run(){
32. Table.printTable(1000);
33. }
34. }
35.
36. public class TestSynchronization4{
37. public static void main(String t[]){
38. MyThread1 t1=new MyThread1();
39. MyThread2 t2=new MyThread2();
40. MyThread3 t3=new MyThread3();
41. MyThread4 t4=new MyThread4();
42. t1.start();
43. t2.start();
44. t3.start();
45. t4.start();
46. }
47. }
Need of Synchronization
To understand the need for synchronization, let’s begin with a simple example that does not use
it—but should. The following program has three simple classes. The first one, Callme, has a
single method named call( ). The call( ) method takes a String parameter called msg.
This method tries to print the msg string inside of square brackets. The interesting thing to notice
is that after call( ) prints the opening bracket and the msg string, it calls Thread .sleep(1000),
which pauses the current thread for one second.
The constructor of the next class, Caller, takes a reference to an instance of the Callme class and
a String, which are stored in target and msg, respectively. The constructor also creates a new
thread that will call this object’s run( ) method. The thread is started immediately.
The run( ) method of Caller calls the call( ) method on the target instance of Callme, passing in
the msg string. Finally, the Synch class starts by creating a single instance of Callme, and three
instances of Caller, each with a unique message string. The same instance of Callme is passed to
each Caller.
To fix the preceding program, you must serialize access to call( ). That is, you must restrict its
access to only one thread at a time. To do this, you simply need to precede call( )’s definition
with the keyword synchronized, as shown here:
class Callme {
synchronized void call(String msg) {
This prevents other threads from entering call( ) while another thread is using it. After
synchronized has been added to call( ), the output of the program is as follows:
[Hello]
[Synchronized]
[World]
1) wait() method
Causes current thread to release the lock and wait until either another thread invokes the notify()
method or the notifyAll() method for this object, or a specified amount of time has elapsed.
The current thread must own this object's monitor, so it must be called from the synchronized
method only otherwise it will throw exception.
Method Description
2) notify() method
Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on
this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the
discretion of the implementation. Syntax:
3) notifyAll() method
Wakes up all threads that are waiting on this object's monitor. Syntax:
wait() sleep()
Let’s now work through an example that uses wait( ) and notify( ). To begin, consider the
following sample program that incorrectly implements a simple form of the producer/ consumer
problem. It consists of four classes: Q, the queue that you’re trying to synchronize;
Producer, the threaded object that is producing queue entries; Consumer, the threaded object
that is consuming queue entries; and PC, the tiny class that creates the single Q, Producer, and
Consumer.
// An incorrect implementation of a producer and consumer.
class Q {
int n;
synchronized int get() {
System.out.println("Got: " + n);
return n;
}
synchronized void put(int n) {
this.n = n;
System.out.println("Put: " + n);
}
}
class Producer implements Runnable {
Q q;
Producer(Q q) {
this.q = q;
new Thread(this, "Producer").start();
}
public void run() {
int i = 0;
while(true) {
q.put(i++);
}
}
}
class Consumer implements Runnable {
Q q;
Consumer(Q q) {
this.q = q;
new Thread(this, "Consumer").start();
}
public void run() {
while(true) {
q.get();
}
}
}
class PC {
public static void main(String args[]) {
Q q = new Q();
new Producer(q);
new Consumer(q);
System.out.println("Press Control-C to stop.");
}
}
Although the put( ) and get( ) methods on Q are synchronized, nothing stops the producer from
overrunning the consumer, nor will anything stop the consumer from consuming the same queue
value twice.
Thus, you get the erroneous output shown here (the exact output will vary with processor
speed and task load):
Put: 1
Got: 1
Got: 1
Got: 1
Got: 1
Got: 1
Put: 2
Put: 3
Put: 4
Put: 5
Put: 6
Put: 7
Got: 7
As you can see, after the producer put 1, the consumer started and got the same 1 five times in a
row. Then, the producer resumed and produced 2 through 7 without letting the consumer have a
chance to consume them.
The proper way to write this program in Java is to use wait( ) and notify( ) to signal in both
directions, as shown here:
Here is some output from this program, which shows the clean synchronous behavior:
Put: 1
Got: 1
Put: 2
Got: 2
Put: 3
Got: 3
Put: 4
Got: 4
Put: 5
Got: 5
1. class Customer{
2. int amount=10000;
3.
4. synchronized void withdraw(int amount){
5. System.out.println("going to withdraw...");
6.
7. if(this.amount<amount){
8. System.out.println("Less balance; waiting for deposit...");
9. try{wait();}catch(Exception e){}
10. }
11. this.amount-=amount;
12. System.out.println("withdraw completed...");
13. }
14.
15. synchronized void deposit(int amount){
16. System.out.println("going to deposit...");
17. this.amount+=amount;
18. System.out.println("deposit completed... ");
19. notify();
20. }
21. }
22.
23. class Test{
24. public static void main(String args[]){
25. final Customer c=new Customer();
26. new Thread(){
27. public void run(){c.withdraw(15000);}
28. }.start();
29. new Thread(){
30. public void run(){c.deposit(10000);}
31. }.start();
32.
33. }}
Output: going to withdraw...
Less balance; waiting for deposit...
going to deposit...
deposit completed...
withdraw completed
Deadlock in java
Deadlock in java is a part of multithreading.
Deadlock can occur in a situation when a thread is waiting for an object lock, that is
acquired by another thread and second thread is waiting for an object lock that is acquired
by first thread. Since, both threads are waiting for each other to release the lock, the
condition is called deadlock.
For example, suppose one thread enters the monitor on object X and another thread
enters the monitor on object Y. If the thread in X tries to call any synchronized method
on Y, it will block as expected. However, if the thread in Y, in turn, tries to call any
synchronized method on X, the thread waits forever, because to access X, it would have
to release its own lock on Y so that the first thread could complete. Deadlock is a difficult
error to debug for two reasons:
o In general, it occurs only rarely, when the two threads time-slice in just the right
way.
o It may involve more than two threads and two synchronized objects. (That is,
deadlock can occur through a more convoluted sequence of events than just
described.)
To understand deadlock fully, it is useful to see it in action. The next example creates two
classes, A and B, with methods foo( ) and bar( ), respectively, which pause briefly before
trying to call a method in the other class. The main class, named Deadlock, creates an A
and a B instance, and then starts a second thread to set up the deadlock condition. The
foo( ) and bar( ) methods use sleep( ) as a way to force the deadlock condition to occur.
// An example of deadlock.
class A {
synchronized void foo(B b) {
String name = Thread.currentThread().getName();
System.out.println(name + " entered A.foo");
try {
Thread.sleep(1000);
} catch(Exception e) {
System.out.println("A Interrupted");
}
System.out.println(name + " trying to call B.last()");
b.last();
}
synchronized void last() {
System.out.println("Inside A.last");
}
}
class B {
synchronized void bar(A a) {
String name = Thread.currentThread().getName();
System.out.println(name + " entered B.bar");
try {
Thread.sleep(1000);
} catch(Exception e) {
System.out.println("B Interrupted");
}
System.out.println(name + " trying to call A.last()");
a.last();
}
synchronized void last() {
System.out.println("Inside A.last");
}
}
class Deadlock implements Runnable {
A a = new A();
B b = new B();
Deadlock() {
Thread.currentThread().setName("MainThread");
Thread t = new Thread(this, "RacingThread");
t.start();
a.foo(b); // get lock on a in this thread.
System.out.println("Back in main thread");
}
public void run() {
b.bar(a); // get lock on b in other thread.
System.out.println("Back in other thread");
}
public static void main(String args[]) {
new Deadlock();
}
}
When you run this program, you will see the output shown here:
MainThread entered A.foo
RacingThread entered B.bar
MainThread trying to call B.last()
RacingThread trying to call A.last()
Because the program has deadlocked, you need to press CTRL-C to end the program. You can
see a full thread and monitor cache dump by pressing CTRL-BREAK on a PC . You will see
that RacingThread owns the monitor on b, while it is waiting for the monitor on a. At the same
time, MainThread owns a and is waiting to get b.
1. class Java_Outer_class{
2. //code
3. class Java_Inner_class{
4. //code
5. }
6. }
1) Nested classes represent a special type of relationship that is it can access all the
members (data members and methods) of outer classincluding private.
2) Nested classes are used to develop more readable and maintainable code because it
logically group classes and interfaces in one place only.
Inner class is a part of nested class. Non-static nested classes are known as inner classes.
There are two types of nested classes non-static and static nested classes.The non-static nested
classes are also known as inner classes.
Type Description
Member Inner Class A class created within class and outside method.
1. class TestMemberOuter1{
2. private int data=30;
3. class Inner{
4. void msg(){System.out.println("data is "+data);}
5. }
6. public static void main(String args[]){
7. TestMemberOuter1 obj=new TestMemberOuter1();
8. TestMemberOuter1.Inner in=obj.new Inner();
9. in.msg();
10. }
11. }
Output:
data is 30