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

Advanced Java Individual Assignment

Threads in Java allow for concurrent execution of tasks by dividing a program's workload into multiple lightweight execution units that can run simultaneously. They provide a way to achieve multitasking and increase efficiency by utilizing system resources like CPUs in parallel. Threads share memory and resources within a process and enable features like synchronization.

Uploaded by

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

Advanced Java Individual Assignment

Threads in Java allow for concurrent execution of tasks by dividing a program's workload into multiple lightweight execution units that can run simultaneously. They provide a way to achieve multitasking and increase efficiency by utilizing system resources like CPUs in parallel. Threads share memory and resources within a process and enable features like synchronization.

Uploaded by

junedijoasli
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 16

Debre Berhan University

College of Computing
Java Programming
Course Code: CoSC 3053
Individual Assignment
Name: Kidus Yared
ID:4109/13
Section: B

What is Thread?
Threads: a lightweight unit of execution within a program. It is a fundamental part of
Java's multithreading support, allowing concurrent execution of multiple tasks or
processes within a single program. It refers to a sequence of instructions that can be
executed independently within a program. It also refers to a separate flow of execution
within a program that can run independently of other threads. Threads allow different
parts of a program to execute concurrently, leading to improved performance,
responsiveness, and utilization of system resources.

Thread can be thought of as an independent path of execution that operates within a


larger program. It enables the program to perform multiple tasks simultaneously, leading
to increased efficiency and responsiveness. They provide a way to achieve multitasking
and increase the efficiency of program execution by dividing tasks into smaller units that
can be executed concurrently. Multiple threads can exist within a single process,
allowing for concurrent execution of tasks.

Java threads are managed by the Java Virtual Machine (JVM) and provide features
such as synchronization, which allows threads to communicate and coordinate with
each other. Threads can be created by extending the Thread class or implementing the
Runnable interface in Java. Each Java program has at least one thread, known as the
main thread, which is automatically created when the program starts. Additional threads
can be created by the programmer to perform specific tasks concurrently. These
threads can run concurrently, meaning they can execute simultaneously, or they can be
scheduled to run at different times based on the program's requirements.

In summary, threads in Java are used to achieve concurrent execution of tasks,


allowing programs to utilize system resources efficiently and provide better
responsiveness. By dividing a program's workload into multiple threads, developers can
take advantage of parallelism and create more efficient and responsive applications.

Multithreading, Multitasking, Multiprocessing


A. Multithreading: is a process of executing two or more threads
simultaneously for maximum utilization of the CPU. It’s also the capability of a
program to execute multiple threads concurrently. It is a technique that allows
different parts of a program to run simultaneously, enabling concurrent
execution of tasks and taking advantage of available system resources. It
saves time as you can perform multiple operations together and the threads
are independent, so it does not block the user to perform multiple operations
at the same time also if an exception occurs in a single thread, it does not
affect other threads. Multithreading enables concurrent execution of tasks by
dividing them into separate threads. It provides the means to create, manage,
and coordinate threads, allowing for parallel execution, improved
performance, and responsiveness in Java applications.

Some examples of Multithreading are Web browser, Word processor Video processor.
B. Multitasking: is the ability of a program to execute multiple tasks
concurrently. It can be achieved using threads, which are lightweight units of
execution within a program. Multitasking enables users to run multiple
applications at the same time and allows for efficient sharing of system
resources among different processes. The ability to perform multitasking in
Java allows for efficient utilization of system resources and enables
concurrent execution of multiple tasks, leading to improved performance and
responsiveness in applications.

Multitasking can be achieved by creating and starting multiple threads, each performing
a specific task or operation. By using multitasking, Java programs can perform tasks
concurrently, which can lead to improved performance, responsiveness, and utilization
of system resources. Threads can execute independently, allowing for parallelism when
running on multi-core processors.

There are two basic types of multitasking in Java:

1. Process-based Multitasking (Multiprocessing): Process-based


multitasking is known as multiprocessing. In multiprocessing, each process
has an address in the memory. In other words, each process allocates a
separate memory area. A process is a

heavyweight. The cost of communication between the processes is high. Saving and
loading of registers, memory maps, and updating lists are required to switch from one
process to another. Java supports multitasking at the process level, where multiple
processes can run concurrently on a computer system. Each process has its own
memory space and resources, and they are managed by the operating system.

2. Thread-based Multitasking (Multithreading): Thread-based multitasking


is known as multithreading in java. At least one process is required for each
thread. A thread is lightweight. The cost of communication between the
threads is low. In this article, we are going to know the details about
multithreading in java. Java's primary mechanism for multitasking is through
threads. A thread is a lightweight unit of execution within a program. It allows
different parts of a program to run concurrently within the same process.
Threads share the same memory space and resources, but each thread has
its own execution context.

C. Multiprocessing: is the execution of multiple processes concurrently, where


each process runs independently and can perform different tasks
simultaneously. Java provides support for multiprocessing through the use of
threads. They require multiple physical processors for executing a complex
process. Multiple threads can be created within a Java program, and each
thread can perform a separate task independently. Threads within a process
share the same memory space, allowing for efficient communication and data
sharing between them.

It's is the utilization of two or more central processing units (CPUs) in a single computer
system. Its definition can vary depending on the context, but generally it refers to a
system's ability to support multiple CPUs and its capacity to distribute work among
them.

Process vs Thread
Process: is an active program that is under execution. It is more than the program
code, as it includes the program counter, process stack, registers, program code etc.
Compared to this, the program code is only the text section. It represents the execution
of a Java application, which can consist of multiple threads. Each Java process has its
own memory space, system resources, and a separate instance of the Java Virtual
Machine (JVM) running the application. When you run a Java program, it starts a new
process that operates independently of other processes. Each process runs
independently and is isolated from other processes, meaning that it has its own memory
space and cannot directly access or modify the memory of other processes. Processes
are managed by the operating system, which schedules their execution, assigns system
resources, and facilitates inter-process communication. Processes communicate with
each other through inter-process communication (IPC) mechanisms, such as pipes,
shared memory, or message passing.

Thread: is a unit of execution within a Java process. It is a lightweight sequence of


instructions that can run concurrently with other threads within the same process. Java
threads are instances of the java.lang. Thread class or can be created by implementing
the java.lang. Runnable interface. Multiple threads within a Java process share the
same memory space, allowing for efficient communication and data sharing between
them. Java's multithreading capabilities allow you to create and manage multiple
threads within a single Java process. This enables concurrent execution of tasks,
improves performance, and enhances responsiveness in applications. By leveraging
threads, you can achieve parallelism and efficiently utilize available system resources.

A thread shares information like data segment, code segment, files, etc. with its peer
threads while it contains its own registers, stack, counter, etc. It’s basically a subpart of
a large process. In a process, all the threads within it are interrelated to each other. A
typical thread contains some information like data segment, code segment, etc. This
information is being shared with their peer threads during execution. The most important
feature of threads is that they share memory, data, resources, etc. with their peer
threads within a process to which they belong.

· Both processes and threads are related to each other and very much similar,
hence creating confusion to understand the differences between both of
them. The process and thread are an independent sequence of execution, but
both are differentiated in a way that processes execute in different memory
spaces, whereas threads of the same process execute in shared memory
space.

o The main difference between a process and a thread is that a process


represents the execution of a Java program and is isolated from other
processes, while a thread is a unit of execution within a Java process and
allows for the concurrent execution of tasks within the same memory space.
Processes have their own memory and resources, whereas threads share
resources within a process. Threads are lightweight and used for achieving
concurrency within a Java program, while processes are independent
instances of Java programs.

Thread-based multitasking and multithreading


A. Thread-based multitasking (concurrent programming): is executing
multiple tasks or activities simultaneously within a program using threads.
There can be two or more threads can be run concurrently. In Java, this can
be achieved by creating multiple threads that perform different tasks
concurrently. Each thread represents an independent flow of control within
the program, allowing for parallel execution of multiple activities. By utilizing
thread-based multitasking, you can improve the efficiency and
responsiveness of your Java program, particularly in scenarios where tasks
can be executed independently or tasks involve waiting for I/O operations. For
example, you can create one thread to handle user input, another thread to
perform time-consuming calculations, and yet another thread to update the
user interface concurrently. This way, different parts of the program can
execute simultaneously, enhancing overall performance.

The process of multi-tasking lets a CPU execute various tasks at the very same time.
The process of multi-threading lets a CPU generate multiple threads out of a task and
process all of them simultaneously. A user can easily perform various tasks
simultaneously with their CPU using multitasking. In thread-based multitasking, the
thread is the smallest unit of dispatchable code. This means that a single program can
perform two or more tasks simultaneously. Example: A Text Editor can format text at the
same time it is printing, as long as these two actions are performed by two separate
threads.

B. Multithreading: is the practice of utilizing multiple threads within a program


to achieve concurrent execution. In Java, multithreading is accomplished by
creating instances of the java.lang.Thread class or implementing the
java.lang.Runnable interface. Each thread represents a separate flow of
control within the program, allowing different parts of the code to execute
simultaneously.

Java's multithreading capabilities enable you to create, manage, and coordinate multiple
threads within a single program. Threads within a Java program share the same
memory space, enabling efficient communication and data sharing. However, it's crucial
to handle thread synchronization and potential race conditions when multiple threads
access shared data to ensure data integrity and avoid conflicts.

By utilizing multithreading in Java, you can effectively utilize system resources, improve
responsiveness, and achieve parallelism within your program, leading to enhanced
performance and better user experience. It is commonly used in scenarios such as
graphical user interfaces (GUIs), server applications, and computationally intensive
tasks. For example, in a GUI application, you can use separate threads to handle user
input, update the interface, and perform background computations simultaneously,
ensuring smooth user interaction. It enables you to enhance the performance and
responsiveness of your program by leveraging the capabilities of modern processors
with multiple cores or support for simultaneous multithreading (SMT). By dividing the
workload into multiple threads, you can achieve parallel execution of tasks, making
efficient use of available system resources.

Multi-thread and Thread synchronization, and priorities


A. Multi-thread: refers to the practice of utilizing multiple threads within a Java
program to achieve concurrent execution. It involves creating and managing
multiple threads that can execute different parts of the program's code
simultaneously. In multi-threaded programs, different threads execute
independently and can perform separate tasks at the same time, allowing for
parallelism and efficient utilization of system resources. Each thread
represents a separate flow of control within the program, enabling concurrent
execution of different parts of the code. Multi-thread is commonly used to
improve performance, responsiveness, and scalability in applications.

Multithreading allows many parts of a program to run simultaneously. These parts are
referred to as threads, and they are lightweight processes that are available within the
process. As a result, multithreading increases CPU utilization through multitasking. By
utilizing multi-threading, Java programs can achieve parallelism and make efficient use
of available system resources, such as CPU cores. Java provides built-in support for
multi-threading through the java.lang. Thread class and the java.lang.Runnable
interface.
Multithreading enables us to run multiple threads concurrently. For instance, in a web
browser, we can have one thread that handles the user interface, and in parallel, we
can have another thread that fetches the data to be displayed. Therefore, multithreading
improves the responsiveness of a system.

B. Thread Synchronization: is the process of coordinating the execution of


multiple threads to ensure orderly and predictable behavior. It’s a way of
programming several threads to carry out independent tasks easily. It is
capable of controlling access to multiple threads to a particular shared
resource. The main reason for using thread synchronization is to prevent
interference between threads. In multi-threaded programs, threads may need
to access shared resources or critical sections of code concurrently.
Synchronization mechanisms, such as locks, semaphores, or monitors, are
used to control access to these shared resources and prevent data corruption
or race conditions. Java provides keywords like synchronized and classes like
Lock and Semaphore for thread synchronization.

Java provides synchronization mechanisms that allow threads to safely access shared
resources. The most commonly used synchronization mechanism in Java is the
synchronized keyword, which can be applied to methods or code blocks. When a thread
encounters a synchronized block or method, it acquires a lock on the associated
monitor, ensuring that only one thread can execute the synchronized code at a time.
Other threads attempting to access the same synchronized block or method will be
blocked until the lock is released. By properly synchronizing access to shared
resources, thread synchronization prevents data corruption and ensures data integrity. It
establishes a happens-before relationship, ensuring that changes made by one thread
are visible to other threads.

It is essential when multiple threads access shared resources concurrently. It helps


maintain data consistency, prevents race conditions, and ensures the correct execution
of multi-threaded programs. However, it's important to use synchronization judiciously to
avoid potential performance bottlenecks or deadlocks. Understanding and applying
proper synchronization techniques are critical for developing robust and thread-safe
Java applications. Additionally, thread synchronization can be used for signaling and
communication between threads, allowing them to coordinate their activities and avoid
unnecessary waiting or busy waiting.

C. Priorities: represent the relative importance of threads for CPU scheduling.


Each thread in Java is assigned a priority value that ranges from 1 to 10. The
larger the integer, the higher the priority. But it is not guaranteed because it
depends on the JVM specification that which scheduling it chooses. Note that
not only JVM a Java programmer can also assign the priorities of a thread
explicitly in a Java program. The thread scheduler uses this integer from each
thread to determine which one should be allowed to execute. The default
priority of a thread is usually inherited from its parent thread.

Thread priorities are used to provide guidance to the Java thread scheduler, which sets
the order in which threads receive CPU time. They are typically used to indicate the
relative importance or urgency of different threads within an application. Threads with
higher priorities are more likely to be scheduled and executed by the scheduler than
threads with lower priorities. It is crucial to remember, however, that thread priorities are
not strictly guaranteed and may vary among platforms and JVM implementations.

The setPriority() function of the Thread class in Java can be used to set the priority of a
thread. The getPriority() method can also be used to retrieve a thread's priority.It is
important to use thread priorities wisely and understand their limitations. While higher-
priority threads are more likely to be scheduled, strict ordering and fairness are not
guaranteed. It is generally not advisable to rely only on thread priority for crucial
synchronization or timing requirements.

Types of Synchronization
Synchronization: is the ability to regulate multiple processes’ access to a shared
resource. It’s a mechanism used to coordinate and control access to shared resources
or critical sections of code in a multi-threaded environment. Multiple threads attempt to
access shared resources at the same time under the Multithreading concept, resulting
in inconsistent outcomes. Synchronization is required for thread-to-thread
communication to be reliable. Synchronization aids in thread interference prevention. It
helps in the prevention of concurrency issues.

Synchronization is crucial for maintaining thread safety and preventing race conditions
and data corruption in multithreaded applications. By properly synchronizing access to
shared resources, developers can ensure the correct and predictable behavior of their
concurrent programs. It ensures that only one thread can access a shared resource or
execute a critical section at a time, preventing conflicts and maintaining data
consistency.

Ø There are two forms of synchronization:

A. Process synchronization: is the coordination between independent


processes running in parallel. It is necessary when multiple processes need
to access shared resources or communicate with each other. Process
synchronization mechanisms include techniques such as semaphores, locks,
and message passing. These mechanisms help prevent race conditions,
deadlocks, and other synchronization-related issues.

It operates in a separate process that is not connected to another. The operating


system allocates resources to the process, such as memory and CPU time. The phrase
“process synchronization” refers to the sharing of capabilities between two or more
processes while guaranteeing data consistency. The Critical Section is a piece of code
that is shared by several processes in a programming language. There are various
methods to prevent critical section problems, such as Peterson’s Solution, but the most
famous is Semaphores.

B.Thread synchronization: is a form of synchronization that focuses on


coordinating the activities of multiple threads within a single process. Threads
are lightweight units of execution that share the same memory space. Thread
synchronization is crucial when multiple threads access shared data
concurrently. Common thread synchronization techniques in Java include
synchronized blocks, locks (such as ReentrantLock), and concurrency utilities
like CountDownLatch and CyclicBarrier.

It refers to the concurrent execution of a vital resource by two or more Threads. A


thread is a subroutine that can run separately within the context of a single process. A
single process can have numerous threads, and the program can schedule all of the
threads to use a vital resource. A single thread, in reality, includes numerous threads.

Types of thread synchronization

Ø There are two types of thread synchronization:

1. Mutual Exclusive: also known as a Mutual Exclusive, allows only one


thread to access shared resources. In other words, it is the property where
only one thread can access a shared resource or a critical section of code at
a time. This prevents conflicts and data inconsistencies. In Java, mutual
exclusion can be achieved using the synchronized keyword or Lock objects. It
will not enable simultaneous access to shared resources.

ü Here is one example of mutual exclusive thread synchronization:


In this example, we have a “PrintJob” class with a “print” method that is declared as
synchronized. This ensures that only one thread can execute the “print” method at a
time.
We create two “PrinterThread” objects, passing the same “PrintJob” instance and
different document names to each thread. When the threads start, they invoke the
“print” method on the shared “PrintJob” object. Due to the synchronized keyword, only
one thread can access the “print” method at a time, ensuring mutual exclusion. As a
result, the documents are printed sequentially, preventing conflicts and maintaining data
consistency. The threads are separate instances, but they synchronize their access to
the shared “PrintJob” object, achieving mutual exclusion.

Implementation:
}public class Counter {
private int count = 0;

public synchronized void increment() {


count++;
}

public synchronized void decrement() {


count--;
}

public synchronized int getCount() {


return count;
}
}

Types of Mutual exclusion threads:

A. Synchronized Method: It provides the synchronized keyword, which can


be applied to methods to achieve mutual exclusion. When a thread enters a
synchronized method, it acquires the lock associated with the object instance
or class. Other threads attempting to execute synchronized methods on the
same object or class must wait until the lock is released. When a method is
declared as synchronized, only one thread can execute that method at a
time, ensuring mutual exclusion.

Example:
public class SynchronizedMethodExample {
private int count = 0;
public synchronized void increment() {
count++;
}
}

B. Synchronized block: Java allows the use of synchronized blocks to create


smaller critical sections within methods. With synchronized blocks, a thread
acquires the lock associated with the specified object or class before
entering the block. A synchronized block allows you to create a smaller
critical section within a method. Only one thread can enter the synchronized
block at a time, ensuring mutual exclusion within that block.
Example:

public class SynchronizedBlock() {


private int count = 0;
private Object lock = new Object();

public void increment() {


// Non-critical section

synchronized (lock) {
// Critical section
count++;
}

// Non-critical section
}
}

C. Static Synchronization: When a static method is declared as


synchronized, only one thread can execute that method at a time for all
instances of the class, ensuring mutual exclusion across all objects.

Example:
public class StaticSynchronizationExample {
private static int count = 0;
public static synchronized void increment() {
count++;
}
}

2. Inter Thread Communication: is a mechanism in which a thread is paused


running in its critical section and another thread is allowed to enter (or lock) in
the same critical section to be executed. It is done with the help of three final
methods defined in the Object class: wait(), notify(), and notifyAll(). The wait()
method puts the current thread into a sleep state and releases the monitor
until some other thread holds the monitor and invokes the notify() or notifyAll()
method. Mailbox service is a typical inter-thread communication method in
real-time operating systems. For example, there are two threads, thread 1
detects the state of the button and sends it's state, and thread 2 reads the
state of the button and turns on or off the LED according to the state of the
button.
ü Here is one example for Inter-Thread Communication:
In this example, the “setMessage” method sets the message content and notifies other
threads waiting on the object. The “getMessage” method retrieves the message and
notifies waiting threads. The “wait()” method suspends the calling thread until it is
notified by another thread using “notify()” or “notifyAll()”. It demonstrate how mutual
exclusion and inter-thread communication can be implemented in Java. By ensuring
mutual exclusion, we prevent concurrent access to shared resources, while inter-thread
communication allows threads to synchronize their actions and share information
effectively.
Implementation:
class Message {
private String content;
private boolean isMessageReady = false;
public synchronized void setMessage(String message) {
while (isMessageReady) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
content = message;
isMessageReady = true;
notifyAll();
}
public synchronized String getMessage() {
while (!isMessageReady) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isMessageReady = false;
notifyAll();
return content;
}
}

Ø The Object class in java contains three final methods that allow threads to
communicate about the lock status of a resource. These methods are wait(),
notify(), and notifyAll().

·Wait(): . It is called inside a synchronized context (synchronized block or


synchronized method) to release the lock and allow other threads to execute.
Object wait methods have three variances, one of which waits indefinitely for
any other thread to call the “notify” or “notifyAll” method on the object to wake
up the current thread. The other two variances place the current thread in wait
for a specific amount of time before they wake up

Example:

package com.journaldev.concurrency
public class Waiter implements Runnable{
private Message msg;
public Waiter(Message m){
this.msg=m;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
synchronized (msg) {
try{
System.out.println(name+" waiting to get notified at
time:"+System.currentTimeMillis());
msg.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(name+" waiter thread got notified at
time:"+System.currentTimeMillis());
//process the message now
System.out.println(name+" processed: "+msg.getMsg());
}
}
}

· notify(): is called inside a synchronized context to notify a waiting thread that it


can proceed. notify method wakes up only one thread waiting on the object
and that thread starts execution. So if there are multiple threads waiting for an
object, this method will wake up only one of them. The choice of thread to
wake depends on the OS implementation of thread management. After
notify() is called, the awakened thread does not immediately regain the lock. It
must wait for the notifying thread to release the lock before it can proceed.

Example:

package com.journaldev.concurrency;
public class Notifier implements Runnable {
private Message msg;
public Notifier(Message msg) {
this.msg = msg;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name+" started");
try {
Thread.sleep(1000);
synchronized (msg) {
msg.setMsg(name+" Notifier work done");
msg.notify();
// msg.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

· notifyAll(): It is called inside a synchronized context to notify all waiting


threads that they can proceed. notifyAll method wakes up all the threads
waiting on the object, although which one will process first depends on the
OS implementation. These methods can be used to implement producer-
consumer problems where consumer threads are waiting for the objects in
Queue and producer threads put objects in the queue and notify the waiting
threads. Let’s see an example where multiple threads work on the same
object and we use wait, notify, and notifyAll methods. After notifyAll() is called,
the awakened threads do not immediately regain the lock. They must wait for
the notification thread to release the lock before they can proceed.

Example:

package com.journaldev.concurrency;
public class WaitNotifyTest {
public static void main(String[] args) {
Message msg = new Message("process it");
Waiter waiter = new Waiter(msg);
new Thread(waiter,"waiter").start();
Waiter waiter1 = new Waiter(msg);
new Thread(waiter1, "waiter1").start();
Notifier notifier = new Notifier(msg);
new Thread(notifier, "notifier").start();
System.out.println("All the threads are started");
}
}

In this example, the Message class represents a shared message object between the
Producer and Consumer threads. The produce() method is used by the producer to set
the content of the message, and the consume() method is used by the consumer to
retrieve the content of the message. The methods are synchronized and use the wait()
and notify() calls to control the execution flow. The producer waits when the message is
not empty, and the consumer waits when the message is empty. The notify() calls notify
the waiting threads to resume execution.

You might also like