You are on page 1of 23

Java multithreading

chapter 26
Multithreading
• Multithreading in Java is a way to run multiple parts of a program at
the same time. Think of it like having multiple people working on
different parts of a project at the same time. Each person can work
independently, but they all contribute to the same goal.

• In Java, each part of a program that runs independently is called a


"thread". When you start a Java program, it automatically creates a
"main" thread that runs the main method of your program. You can
create additional threads by creating objects of the Thread class and
calling their start() method.
• Each thread runs independently of the others, so you can have multiple
threads doing different things simultaneously. For example, one thread might
be downloading data from the internet while another thread is processing
that data. This can make your program run faster and more efficiently, since
you don't have to wait for one task to finish before starting the next.
• However, multithreading can also be tricky to manage. You need to make
sure that different threads don't interfere with each other or access the same
data at the same time, which can cause errors and crashes. To prevent this,
Java provides several synchronization mechanisms, such as the synchronized
keyword and the Lock and Semaphore classes, which allow you to control
access to shared resources and prevent race conditions.
run()
• When you create a thread in Java, you typically pass an object that
implements the Runnable interface to the Thread constructor. This
object must define a run() method that contains the code to be
executed by the thread.
• In Java, run() is a method that is part of the Runnable interface. This
method defines the code to be executed by a thread when it is
started.
Code in the main thread continues to run while the new thread
executes in the backgroun
In this example, the MyTask
class implements the
Runnable interface and
defines a run() method that
simply prints a message to
the console. The Main class
creates a new thread and
passes a MyTask object to
its constructor, then starts
the thread. As a result, both
the main thread and the
new thread will execute
simultaneously, with the
new thread executing the
code in the run() method of
the MyTask object.
Thread.sleep()
• In Java, the Thread.sleep() method causes the current thread to pause execution for a specified
period of time. This can be useful for controlling the timing of your code, or for simulating
delays in a program.
• In Java, Thread.sleep(0) is used to give up the current thread's time slice and allow other
threads to run. It means that the current thread will pause for a very short time (usually less
than 1 millisecond) and then continue executing.
• We may need to use Thread.sleep(0) in situations where we have multiple threads competing
for CPU time, and we want to give other threads a chance to run. For example, if we have a
loop that runs for a long time, and we want to allow other threads to execute during the loop,
we can insert Thread.sleep(0) inside the loop to pause the current thread for a very short time
and allow other threads to run.
• However, it's important to note that Thread.sleep(0) is not a guaranteed way to yield the CPU
time to other threads, and its behavior can vary depending on the operating system and the
JVM implementation.
join()
• join() is a method in Java that is used to wait for a thread to complete
its execution before moving on to the next instruction. It is a
convenient way to synchronize the execution of multiple threads and
ensures that the threads finish executing in a specific order.

• The join() method is called on a th


The -> syntax in the given code is part of a lambda expression in Java.

A lambda expression is a way to create a concise implementation of a functional interface, which is an


interface with a single abstract method. In this case, the Thread constructor expects a Runnable object,
which is a functional interface with a single method void run().

The -> syntax is used to separate the lambda's parameters from its body. In the given code, the lambda
expression takes no parameters (since Runnable has no parameters) and its body is the block of code
inside the curly braces {}.

So, the lambda expression () -> { ... } is equivalent to an anonymous implementation of the Runnable
interface, like this: new Runnable() { @Override public void run() { ...} }
get name of thread

Thread.currentThread().getName());
Race condition
• A race condition in Java threading occurs when two or more threads
access shared data or resources concurrently without proper
synchronization. When a race condition occurs, the outcome of the
program depends on the order in which the threads execute, which is
unpredictable and can lead to unexpected results.
Race
• Here the output can be anything due to race condition.
Thread-0 Thread-2 Thread-2 Thread-2 Thread-2 Thread-2 Thread-1
Thread-1 Thread-1 Thread-1 Thread-1 Thread-0 Thread-0 Thread-0
Thread-0
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
locking a thread
• In Java, a thread lock is a mechanism used to ensure that only one thread
can access a shared resource at a time. The purpose of a lock is to prevent
multiple threads from executing the same block of code or accessing the
same object concurrently, which could result in race conditions, data
corruption, or other issues.
• When a thread acquires a lock on an object, it gains exclusive access to
that object and can perform any operation on it. Other threads that try to
access the same object will be blocked .
• In Java, locks are implemented using the synchronized keyword or by
using explicit lock objects provided by the java.util.concurrent.locks
package.
lock() method
• We define two threads, t1 and t2, which both increment the counter
variable one million times. To ensure that access to the counter
variable is synchronized, we surround each increment operation with
calls to lock() and unlock() methods of the lock object.
• The lock() method blocks the current thread until it acquires the lock.
If the lock is already held by another thread, the current thread waits
until the lock is released. The unlock() method releases the lock,
allowing another thread to acquire it.
• In Java, try...finally blocks are commonly used for resource cleanup. In
the context of threads, try...finally blocks are often used to ensure
that locks are released in case an exception occurs while a thread
holds the lock.

• In the example you provided, try...finally blocks are used to ensure


that locks are properly released. Without these blocks, if an exception
occurs while a thread holds a lock, the lock may not be released,
potentially causing deadlocks or other issues.
thread synchronization
• If one thread is in the process of updating a shared object and another thread
also tries to update it, it’s unclear which thread’s update takes effect. When
this happens, the program’s behavior cannot be trusted.
• The problem can be solved by giving only one thread at a time exclusive access
to code that manipulates the shared object. During that time, other threads
desiring to manipulate the object are kept waiting.
• This process, called thread synchronization, coordinates access to shared data
by multiple concurrent threads
• By synchronizing threads in this manner, you can ensure that each thread
• accessing a shared object excludes all other threads from doing so
simultaneously—this is called mutual exclusion.
thread synchronization
• A common way to perform synchronization is to use Java’s built-in
monitors. Every object has a monitor and a monitor lock (or intrinsic
lock). The monitor ensures that its object’s monitor lock is held by a
maximum of only one thread at any time.
• Other threads attempting to perform an operation that requires the
same lock will be blocked until the first thread releases the lock, at
which point the blocked threads may attempt to acquire the lock and
proceed with the operation.
• To specify that a thread must hold a monitor lock to execute a block of
code, the code should be placed in a synchronized statement. Such
code is said to be guarded by the monitor lock; a thread must acquire
the lock to execute the guarded statements.
synchronized ( object )
{ statements } // end synchronized statement
• Java also allows synchronized methods. Before executing, a non-static
synchronized method must acquire the lock on the object that’sused to
call the method.
• The race condition in previous example is solved below.

You might also like