0% found this document useful (0 votes)
2 views3 pages

Java Thread Synchronization Example

The document contains Java code for a synchronization example involving three threads that print messages using a synchronized method. It includes three classes: Synch, CallMe, and Caller, where Synch initiates the threads, CallMe defines the synchronized method, and Caller represents the individual threads. The output of the program is 'Richa is Best', and a GitHub link is provided for further reference.

Uploaded by

richa.guptanag
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views3 pages

Java Thread Synchronization Example

The document contains Java code for a synchronization example involving three threads that print messages using a synchronized method. It includes three classes: Synch, CallMe, and Caller, where Synch initiates the threads, CallMe defines the synchronized method, and Caller represents the individual threads. The output of the program is 'Richa is Best', and a GitHub link is provided for further reference.

Uploaded by

richa.guptanag
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Java_Assignment_9

Richa Gupta
22070126087
AIML B1
[Link]

package java_assignment_9;

// Class representing a simple synchronization example


public class Synch {
public static void main(String[] args) {

// Creating an instance of CallMe, which contains the me


CallMe target = new CallMe();

// Creating three Caller objects, each associated with t


Caller object1 = new Caller(target, "Richa");
Caller object2 = new Caller(target, "is");
Caller object3 = new Caller(target, "best");

// Start the threads associated with each Caller object


[Link]();
[Link]();
[Link]();

try {
// Wait for each thread to finish executing
[Link]();
[Link]();
[Link]();
} catch (InterruptedException e) {
// Handle the case where a thread is interrupted whi

Java_Assignment_9 1
[Link]();
}
}
}

[Link]

package java_assignment_9;

// Class representing a method that prints a message with synchr


public class CallMe {

// Method for printing a message with synchronization


synchronized public void call(String msg) {
// Print the message
[Link](msg);
try {
// Simulate some work being done by sleeping for 1 s
[Link](1000);
} catch (InterruptedException e) {
// Handle the case where the thread is interrupted w
[Link]();
}
// Add a space after printing the message
[Link](" ");
}
}

[Link]

package java_assignment_9;

// Class representing a caller that invokes a synchronized metho


public class Caller implements Runnable {
Thread t; // Thread associated with this caller
String msg; // Message to be passed to the synchronized meth

Java_Assignment_9 2
CallMe target; // Target object containing the synchronized

// Constructor to initialize the caller with a target object


public Caller(CallMe targ, String s) {
target = targ;
msg = s;
t = new Thread(this);
}

// Method representing the execution logic of the caller


@Override
public void run() {
// Synchronize on the target object to ensure thread saf
synchronized (target) {
// Call the synchronized method of the target object
[Link](msg);
}
}
}

Output: Richa is Best

Github link: [Link]

Java_Assignment_9 3

Common questions

Powered by AI

The Java code employs a Producer-Consumer design pattern where the `CallMe` class acts as a shared resource (Consumer) with synchronized access, and the `Caller` classes function as Producers that interact with this shared resource in a controlled manner. This pattern effectively manages concurrent thread interactions by regulating access through synchronization, making it suitable for scenarios where multiple threads need safe and sequential access to shared resources. Its effectiveness lies in providing a structured way to handle synchronization, thus avoiding potential race conditions or data integrity issues without degrading performance significantly .

Each Caller object has its own thread associated with the `CallMe` object to allow concurrent execution of the message printing functionality. By assigning a separate thread to each Caller instance, the program can attempt to call the synchronized method concurrently, which highlights the need for synchronization to ensure orderly access. This setup demonstrates how threads operate in a multithreaded environment where synchronization is crucial to avoid race conditions .

The `join()` method is used in the main method to ensure that the main thread waits for the completion of other threads before proceeding. This means the main thread will only continue its execution after all individual Caller threads have completed their tasks, ensuring a defined point in the program where all threads have finished. Omitting `join()` would cause the main thread to finish execution without waiting, potentially terminating before child threads complete, and could result in unfinished thread operations if the main program concludes prematurely .

The `Caller` class ensures that the message calling sequence remains synchronized by using a synchronized block within its `run` method. It synchronizes on the `CallMe` target object, ensuring that only one thread can access the `call` method of the `CallMe` class at any given time. This prevents other threads from entering the method while it is being executed by another thread, thus maintaining sequence integrity and preventing interleaved execution of messages .

The `Thread.sleep(1000)` statement is used to simulate a delay in each thread's execution during message printing. By causing the executing thread to pause for one second, it ensures that the timing gaps between each step in the output are visually apparent, helping highlight the need for and effect of synchronization. It does not affect the synchronization mechanism itself but allows clear visualization of each step being independently completed before the lock is released .

To allow flexible message delay timing, you can introduce a delay parameter in the `Caller` class that specifies the amount of time each thread should sleep. This can be passed through the constructor and then used within the `run` method to replace the hardcoded `Thread.sleep(1000)`. By doing so, each `Caller` object could have a different delay, allowing for more dynamic and flexible execution timings .

The code handles `InterruptedException` which may occur if a thread is interrupted while it is in a sleeping state during its execution (`Thread.sleep()`). Handling such exceptions is crucial in a multithreaded environment because interrupted threads need proper management to ensure they do not leave processes in an unstable state, which can lead to unpredictable behavior or resource leaks if not handled .

An improvement in error handling for thread interruptions could be achieved by implementing a robust interruption handling strategy. Instead of simply printing the stack trace, the `run` method in the `Caller` class could catch `InterruptedException` and implement a specific recovery or fallback strategy such as logging the interruption to a file, attempting to restart the operation, or gracefully terminating and cleaning up resources. This approach would provide better insight and control over unexpected state changes, ensuring reliability and robustness in handling interruptions .

The main purpose of synchronization in the Java code example is to ensure that the `call` method of the `CallMe` class is accessed by only one thread at a time. This prevents concurrent threads from interleaving their executions in a way that could result in incorrect outputs. The `synchronized` keyword ensures that once a thread starts executing the `call` method, other threads must wait until the first thread completes its operation, thus maintaining the integrity of the shared resource .

Without the synchronized keyword, the messages printed by the `call` method would no longer be guaranteed to appear in sequence. Multiple threads could potentially execute this method concurrently, leading to interleaved message parts and thus, an inconsistent or jumbled output. Using synchronization guarantees that only one thread accesses the shared resource at a time, ensuring that each complete message is output consecutively and predictably .

You might also like