Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
19 views

JAVA 11 MultithreadedProgramming

Uploaded by

kiranchaitanyab
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views

JAVA 11 MultithreadedProgramming

Uploaded by

kiranchaitanyab
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 92

Multithreaded Programming

Thread-Based Multi-Tasking
• Thread-based multi-tasking is about a single program
executing concurrently several tasks e.g. a text editor
printing and spell-checking text.
• Threads are lightweight tasks:
1) they share the same address space
2) they cooperatively share the same process
3) inter-thread communication is inexpensive
4) context-switching from one thread to another is
low-cost
• Java multi-tasking is thread-based.
Reasons for Multi-Threading
• Multi-threading enables to write efficient programs that
make the maximum use of the CPU, keeping the idle time to
a minimum.
• There is plenty of idle time for interactive, networked
applications:
1) the transmission rate of data over a network is much
slower than the rate at which the computer can process it
2) local file system resources can be read and written at a
much slower rate than can be processed by the CPU
3) of course, user input is much slower than the computer
Reasons for Multi-Threading
• Multitasking threads require less overhead than multitasking
processes. Processes are heavyweight tasks that require their
own separate address spaces.
• Interprocess communication is expensive and limited.
Context switching from one process to another is also costly.
• Threads, on the other hand, are lighter weight. They share the
same address space and cooperatively share the same
heavyweight process. Interthread communication is
inexpensive, and context switching from one thread to the
next is lower in cost.
• While Java programs make use of process-based multitasking
environments, process-based multitasking is not under Java’s
control. However, multithreaded multitasking is.
Thread Lifecycle
• Thread exists in several states:
1) ready to run
2) running
3) a running thread can be suspended
4) a suspended thread can be resumed
5) a thread can be blocked when waiting for a resource
6) a thread can be terminated
• Once terminated, a thread cannot be resumed.
Thread Lifecycle
sleep(500)
Active

wake up
JVM
Born start() suspend()

resume()

Runnable
Blocked
stop() wait
stop()
notify

block on I/O
Dead I/O available
Thread Lifecycle
• New state – After the creations of Thread instance the thread is in this
state but before the start() method invocation. At this point, the thread
is considered not alive.
• Runnable (Ready-to-run) state – A thread start its life from Runnable
state. A thread first enters runnable state after the invoking of start()
method but a thread can return to this state after either running,
waiting, sleeping or coming back from blocked state also. On this state a
thread is waiting for a turn on the processor.
• Running state – A thread is in running state that means the thread is
currently executing. There are several ways to enter in Runnable state
but there is only one way to enter in Running state: the scheduler select
a thread from runnable pool.
• Dead state – A thread can be considered dead when its run() method
completes. If any thread comes on this state that means it cannot ever
run again.
• Blocked - A thread can enter in this state because of waiting the
resources that are hold by another thread.
CREATING THREAD
Creating a Thread
• In the most general sense, you create a thread by
instantiating an object of type Thread.
• Java defines two ways in which this can be
accomplished:
– You can implement the Runnable interface.
– You can extend the Thread class, itself.
• When a Java program starts up, one thread
begins running immediately. This is usually called
the main thread of our program because it is the
one that is executed when our program begins.
Implementing Runnable
• The easiest way to create a thread is to create a
class that implements the Runnable interface.
Runnable abstracts a unit of executable code.
• You can construct a thread on any object that
implements Runnable.
• To implement Runnable, a class need only
implement a single method called run( ), which
is declared like this:
public void run( )
• Inside run( ), you will define the code that
constitutes the new thread. It is important to
understand that run( ) can call other methods,
use other classes, and declare variables, just
like the main thread can.
• The only difference is that run( ) establishes
the entry point for another, concurrent thread
of execution within your program. This thread
will end when run( ) returns.
• After you create a class that implements
Runnable, you will instantiate an object of type
Thread from within that class.
• Thread defines several constructors. The one that
we will use is shown here:
Thread(Runnable threadOb, String threadName)
• After the new thread is created, it will not start running
until you call its start( ) method, which is declared within
Thread.
• In essence, start( ) executes a call to run( ).
// Create a second thread.
class NewThread implements Runnable {
Thread t;

NewThread() {
// Create a new, second thread
t = new Thread(this, "Demo Thread");
System.out.println("Child thread: " + t);
t.start(); // Start the thread
}

// This is the entry point for the second thread.


public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i);
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}
class ThreadDemo {
public static void main(String args[]) {
new NewThread(); // create a new thread

try {
for(int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}
• Inside NewThread’s constructor, a new Thread
object is created by the following statement:
t = new Thread(this, "Demo Thread");
• Passing this as the first argument indicates that you
want the new thread to call the run( ) method on this
object.
• Next, start( ) is called, which starts the thread of
execution beginning at the run( ) method. This causes
the child thread’s for loop to begin.
• After calling start( ), NewThread’s constructor returns to
main( ).
• When the main thread resumes, it enters its for loop.
Both threads continue running, sharing the CPU in single
core systems, until their loops finish.
• The output produced by this program is as
follows. (Your output may vary based upon the
specific execution environment.)
Thread Class Methods

• Start: a thread by calling start its run method


• Sleep: suspend a thread for a period of time
• Run: entry-point for a thread
• Join: wait for a thread to terminate
• isAlive: determine if a thread is still running
• getPriority: obtain a thread’s priority
• getName: obtain a thread’s name
New Thread: By Implementing Runnable
Interface
New Thread: Runnable
To create a new thread by implementing the Runnable
interface:
1) create a class that implements the run method (inside this
method, we define the code that constitutes the new
thread):
public void run()
2) instantiate a Thread object within that class, a possible
constructor is:
Thread(Runnable threadOb, String threadName)
3) call the start method on this object (start calls run):
void start()
Example: New Thread 1(using Runnable)

• A class NewThread that implements Runnable:


class NewThread implements Runnable {
Thread t;
//Creating and starting a new thread. Passing this to the Thread
constructor – the new thread will call this object’s run method:
NewThread() {
t = new Thread(this, "Demo Thread");
System.out.println("Child thread: " + t);
t.start();
}
Example: New Thread 2(using Runnable)

//This is the entry point for the newly created thread – a five-iterations loop
//with a half-second pause between the iterations all within try/catch:
public void run() {
try {
for (int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i);
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}
Example: New Thread 3

class ThreadDemo {
public static void main(String args[]) {
//A new thread is created as an object of
// NewThread:
new NewThread();
//After calling the NewThread start method,
// control returns here.
Example: New Thread 4
//Both threads (new and main) continue concurrently.
//Here is the loop for the main thread:
try {
for (int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}
New Thread: By Extending Thread class
New Thread: By Extending Thread class
• There are two steps:
1. create a new class that extends Thread and
override run( ) method available in Thread
class. This method provides an entry point
for the thread and you will put your
complete business logic inside this method.
2. Create Thread object and you can start it by
calling start() method, which executes a call
to run( ) method.
Example 1
Example 2
Example 3
Example 3
Example 3
Daemon Threads
Thread Groups
• Every Java thread is a member of a thread group.
• Thread groups provide a mechanism for collecting multiple threads into a
single object and manipulating those threads all at once, rather than
individually.
• For example, you can start or suspend all the threads within a group with a
single method call.
• Java thread groups are implemented by the “ThreadGroup” class in the
java.lang package.
• The runtime system puts a thread into a thread group during thread
construction.
• When you create a thread, you can either allow the runtime system to put the
new thread in some reasonable default group or you can explicitly set the
new thread's group.
• The thread is a permanent member of whatever thread group it joins upon its
creation--you cannot move a thread to a new group after the thread has been
created
The ThreadGroup Class
• The “ThreadGroup” class manages groups of threads for Java
applications.
• A ThreadGroup can contain any number of threads.
• The threads in a group are generally related in some way, such
as who created them, what function they perform, or when
they should be started and stopped.
• ThreadGroups can contain not only threads but also other
ThreadGroups.
• The top-most thread group in a Java application is the thread
group named main.
• You can create threads and thread groups in the main group.
• You can also create threads and thread groups in subgroups of
main.
Creating a Thread Explicitly in a Group
• A thread is a permanent member of whatever thread group it joins when its
created--you cannot move a thread to a new group after the thread has been
created.
• Thus, if you wish to put your new thread in a thread group other than the
default, you must specify the thread group explicitly when you create the
thread.
• The Thread class has three constructors that let you set a new thread's group:

public Thread(ThreadGroup group, Runnable target)


public Thread(ThreadGroup group, String name)
public Thread(ThreadGroup group, Runnable target,
String name)
• Each of these constructors creates a new thread, initializes it based on the
Runnable and String parameters, and makes the new thread a member of the
specified group.
For example:
ThreadGroup myThreadGroup = new ThreadGroup("My Group of Threads");
Thread myThread = new Thread(myThreadGroup, "a thread for my group");
THE MAIN THREAD
The Main Thread
• When a Java program starts up, one thread begins
running immediately. This is usually called the main
thread of your program, because it is the one that is
executed when your program begins. The main
thread is important for two reasons:
• It is the thread from which other “child” threads
will be spawned.
• Often, it must be the last thread to finish execution
because it performs various shutdown actions.
The Main Thread
• Although the main thread is created automatically when your
program is started, it can be controlled through a Thread object.
• To do so, you must obtain a reference to it by calling the method
currentThread( ), which is a public static member of Thread.
• Its general form is shown here:
static Thread currentThread( )
• This method returns a reference to the thread in which it is
called.
• Once you have a reference to the main thread, you can control
it just like any other thread.
• In this program, a reference to the current thread (the main
thread, in this case) is obtained by calling currentThread( ), and
this reference is stored in the local variable t.
• Next, the program displays information about the thread. The
program then calls setName( ) to change the internal name of
the thread.
• Information about the thread is then redisplayed. Next, a loop
counts down from five, pausing one second between each line.
• The pause is accomplished by the sleep( ) method. The
argument to sleep( ) specifies the delay period in milliseconds.
• Notice the try/catch block around this loop. The sleep( )
method in Thread might throw an InterruptedException.
• This would happen if some other thread wanted to interrupt
this sleeping one.
• Here is the output generated by this program:
EXTENDING THREAD
• The second way to create a thread is to create
a new class that extends Thread, and then to
create an instance of that class.
• The extending class must override the run( )
method, which is the entry point for the new
thread. It must also call start( ) to begin
execution of the new thread.
// Create a second thread by extending Thread
class NewThread extends Thread {

NewThread() {
// Create a new, second thread
super("Demo Thread");
System.out.println("Child thread: " + this);
start(); // Start the thread
}

// This is the entry point for the second thread.


public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i);
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}
class ExtendThread {
public static void main(String args[]) {
new NewThread(); // create a new thread

try {
for(int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}
• This program generates the same output as
the preceding version.
• As you can see, the child thread is created by
instantiating an object of NewThread, which is
derived from Thread.
• Notice the call to super( ) inside NewThread.
This invokes the following form of the Thread
constructor:
public Thread(String threadName)
Thread or Runnable
• The Thread class defines several methods that can be overridden by a
derived class. Of these methods, the only one that must be overridden
is run( ).
• This is, of course, the same method required when you implement
Runnable. Many Java programmers feel that classes should be
extended only when they are being enhanced or modified in some way.
• So, if you will not be overriding any of Thread’s other methods, it is
probably best simply to implement Runnable.
• Also, by implementing Runnable, your thread class does not need to
inherit Thread, making it free to inherit a different class.
• Ultimately, which approach to use is up to you. However, throughout
the rest of this chapter, we will create threads by using classes that
implement Runnable.
CREATING MULTIPLE THREADS
Creating Multiple Threads
• So far, you have been using only two threads:
the main thread and one child thread.
// Create multiple threads.
class NewThread implements Runnable {
String name; // name of thread
Thread t;

NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
t.start(); // Start the thread
}

// This is the entry point for thread.


public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println(name + "Interrupted");
}
System.out.println(name + " exiting.");
}
}
class MultiThreadDemo {
public static void main(String args[]) {
new NewThread("One"); // start threads
new NewThread("Two");
new NewThread("Three");

try {
// wait for other threads to end
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}

System.out.println("Main thread exiting.");


}
}
Using Isalive( ) And Join( )
Using Isalive( ) And Join( )
• As mentioned, often you will want the main thread to
finish last.
• In the preceding examples, this is accomplished by
calling sleep( ) within main( ), with a long enough delay
to ensure that all child threads terminate prior to the
main thread.
• However, this is hardly a satisfactory solution, and it also
raises a larger question: How can one thread know when
another thread has ended?
• Fortunately, Thread provides a means by which you can
answer this question.
Using Isalive( ) And Join( )
• Two ways exist to determine whether a thread
has finished. First, you can call isAlive( ) on the
thread.
final boolean isAlive( )
• While isAlive( ) is occasionally useful, the
method that you will more commonly use to
wait for a thread to finish is called join( ),
shown here:
final void join( ) throws InterruptedException
Using Isalive( ) And Join( )
• This method waits until the thread on which it
is called terminates. Its name comes from the
concept of the calling thread waiting until the
specified thread joins it.
• Additional forms of join( ) allow you to specify
a maximum amount of time that you want to
wait for the specified thread to terminate.
// Using join() to wait for threads to finish.
class NewThread implements Runnable {
String name; // name of thread
Thread t;

NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
t.start(); // Start the thread
}

// This is the entry point for thread.


public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println(name + " interrupted.");
}
System.out.println(name + " exiting.");
}
}
class DemoJoin {
public static void main(String args[]) {
NewThread ob1 = new NewThread("One");
NewThread ob2 = new NewThread("Two");
NewThread ob3 = new NewThread("Three");

System.out.println("Thread One is alive: "


+ ob1.t.isAlive());
System.out.println("Thread Two is alive: "
+ ob2.t.isAlive());
System.out.println("Thread Three is alive: "
+ ob3.t.isAlive());
// wait for threads to finish
try {
System.out.println("Waiting for threads to finish.");
ob1.t.join();
ob2.t.join();
ob3.t.join();
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}

System.out.println("Thread One is alive: "


+ ob1.t.isAlive());
System.out.println("Thread Two is alive: "
+ ob2.t.isAlive());
System.out.println("Thread Three is alive: "
+ ob3.t.isAlive());

System.out.println("Main thread exiting.");


}
}
Thread Priorities
Thread Priority
• Each thread is assigned a default priority of
Thread.NORM_PRIORITY. You can reset the
priority using setPriority(int priority).

• Some constants for priorities include


Thread.MIN_PRIORITY
Thread.MAX_PRIORITY
Thread.NORM_PRIORITY

62
SYNCHRONIZATION
Synchronization
• 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.
• Key to synchronization is the concept of the monitor. A monitor is
an object that is used as a mutually exclusive lock. Only one
thread can own a monitor at a given time.
• When a thread acquires a lock, it is said to have entered the
monitor. All other threads attempting to enter the locked monitor
will be suspended until the first thread exits the monitor.
• These other threads are said to be waiting for the monitor. A
thread that owns a monitor can reenter the same monitor if it so
desires.
Threads: Synchronization
• How to prevent two threads from
simultaneously writing and reading the same
object?
• Java implementation of monitors:
1) classes can define so-called synchronized
methods
2) each object has its own implicit monitor
that is automatically entered when one of the
object’s synchronized methods is called
3) once a thread is inside a synchronized
method, no other thread can call any other
synchronized method on the same object
Thread Synchronization

A shared resource may be corrupted if it is


accessed simultaneously by multiple threads. For
example, two unsynchronized threads accessing
the same bank account may cause conflict.

Step balance thread[i] thread[j]

1 0 newBalance = bank.getBalance() + 1;
2 0 newBalance = bank.getBalance() + 1;
3 1 bank.setBalance(newBalance);
4 1 bank.setBalance(newBalance);

66
Example: Showing Resource Conflict
• Objective: Write a program that demonstrates the problem of resource
conflict.
• Suppose that you create and launch one hundred threads, each of which
adds a penny to an account. Assume that the account is initially empty.

java.lang.Runnable
-char token
100 1 1 1
AddAPennyTask
+getToken AccountWithoutSync Account
+setToken
+paintComponet -bank: Account -balance: int
+mouseClicked
+run(): void -thread: Thread[]
+getBalance(): int
+deposit(amount: int): void
+main(args: String[]): void

AccountWithoutSync

67
Race Condition
What, then, caused the error in the example? Here is a possible scenario:
Step balance Task 1 Task 2

1 0 newBalance = balance + 1;
2 0 newBalance = balance + 1;
3 1 balance = newBalance;
4 1 balance = newBalance;
);

• The effect of this scenario is that Task 1 did nothing, because in


Step 4 Task 2 overrides Task 1's result.
• Obviously, the problem is that Task 1 and Task 2 are accessing a
common resource in a way that causes conflict.
• This is a common problem known as a race condition in
multithreaded programs.

68
Race Condition
Step balance Task 1 Task 2

1 0 newBalance = balance + 1;
2 0 newBalance = balance + 1;
3 1 balance = newBalance;
4 1 balance = newBalance;
);

• A class is said to be thread-safe if an object of the class does not


cause a race condition in the presence of multiple threads.
• As demonstrated in the preceding example, the Account class is
not thread-safe.

69
The synchronized keyword
• To avoid race conditions, more than one thread must be prevented
from simultaneously entering certain part of the program, known as
critical region.
• The critical region is the entire deposit method.
• There are several ways to correct the problem
– One approach is to make Account thread-safe by adding the
synchronized keyword in the deposit method in Line 45 as
follows:
public synchronized void deposit(double amount)
– Use the synchronized keyword to synchronize the method so
that only one thread can access the method at a time.

70
Synchronizing Instance Methods &
Static Methods

• A synchronized method acquires a lock before it executes.


• In the case of a synchronized method, the lock is on the
object for which the method was invoked.
• In the case of a static method, the lock is on the class.
• If one thread invokes a synchronized instance method
(respectively, static method) on an object, the lock of that
object (respectively, class) is acquired first, then the method
is executed, and finally the lock is released.
• Another thread invoking the same method of that object
(respectively, class) is blocked until the lock is released.

71
Synchronizing Instance Methods &
Static Methods
• With the deposit method synchronized, the preceding scenario
cannot happen.
• If Task 2 starts to enter the method, and Task 1 is already in the
method, Task 2 is blocked until Task 1 finishes the method.

Task 1 Task 2

Acquire a-char
locktoken
on the object account -char token

+getToken +getToken
-char token +setToken +setToken
+paintComponet +paintComponet
Execute
+getToken the deposit method
+mouseClicked +mouseClicked
+setToken
+paintComponet Wait to acquire the lock
-char token
+mouseClicked
-char token
+getToken Release the lock
+setToken
+getToken
+paintComponet
-char token Acqurie a lock
+setToken on the object account
+mouseClicked
+paintComponet
+getToken -char token
+mouseClicked
+setToken
+paintComponet Execute the deposit method
+getToken
+mouseClicked +setToken
+paintComponet
-char token
+mouseClicked
+getToken Release the lock
+setToken
+paintComponet

72
Synchronizing Statements
• Invoking a synchronized instance method of an object acquires a
lock on the object, and invoking a synchronized static method of a
class acquires a lock on the class.
• A synchronized statement can be used to acquire a lock on any
object, not just this object, when executing a block of the code in a
method.
• This block is referred to as a synchronized block. The general form of
a synchronized statement is as follows:

synchronized (expr) {
statements;
}

• The expression expr must evaluate to an object reference.


• If the object is already locked by another thread, the thread is
blocked until the lock is released.
• When a lock is obtained on the object, the statements in the
synchronized block are executed, and then the lock is released. 73
Thread Synchronization

• Language keyword: synchronized


• Takes out a monitor lock on an object
– Exclusive lock for that thread
• If lock is currently unavailable, thread will be
blocked
Thread Synchronization

• Protects access to code, not to data


– Make data members private
– Synchronize accessor methods
• Puts a “force field” around the locked object
so no other threads can enter
• Actually, it only blocks access to other synchronizing
threads
Interthread Communication
Interthread Communication
• The preceding examples unconditionally
blocked other threads from asynchronous
access to certain methods.
• This use of the implicit monitors in Java
objects is powerful, but you can achieve a
more subtle level of control through
interprocess communication.
Interthread Communication
• Java includes an elegant interprocess communication
mechanism via the wait( ), notify( ), and notifyAll( ) methods

• 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.");


}
}
• 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
// A correct implementation of a producer and consumer.
class Q {
int n;
boolean valueSet = false;

synchronized int get() {


while(!valueSet)
try {
wait();

} catch(InterruptedException e) {
System.out.println("InterruptedException caught");
}

System.out.println("Got: " + n);


valueSet = false;
notify();
return n;
}

synchronized void put(int n) {


while(valueSet)
try {
wait();
} catch(InterruptedException e) {
System.out.println("InterruptedException caught");
}

this.n = n;
valueSet = true;
System.out.println("Put: " + n);
notify();
}
}
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 PCFixed {
public static void main(String args[]) {
Q q = new Q();
new Producer(q);
new Consumer(q);

System.out.println("Press Control-C to stop.");


}
}
DEADLOCK
// 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();
}
}
Discussion
Why Threading
• All threads are objects. Therefore, if you want to run 10 threads,
then you have to create 10 objects (either of similar class or of
different classes).
• Q. Normally if we create 10 objects of any class then they will also
work like thread
• A. Concept of threading provides parallel execution of more than
one tasks. You can create 10 objects without multithreading concept
but you cannot force them to run in parallel. Whereas, with
multithreading, you can do it.
– Advantage of thread is that whenever a thread is sleeping, execution
control goes to some other thread. It does not wait for the thread to be
awaken. Whereas in normal execution it waits.
• If you want to see the benefits of multithreading, take an example
where it is really required.
• ‘Thread.sleep()’ can be used in any place in a class; it does not
matter whether that class inherits Thread class or not.

You might also like