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

PyQt5 Thread Execution Example

The document describes a program that creates two threads - one that prints "Thread1" every 2 seconds and one that prints "Thread2" every 4 seconds. It does this by extending the Thread class to create two instances that override the run method - one prints "Thread1" and sleeps for 2 seconds in a for loop 5 times, the other prints "Thread2" and sleeps for 4 seconds in a for loop 5 times. The main method then starts both threads to run concurrently.

Uploaded by

Rushi Pandav
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)
30 views3 pages

PyQt5 Thread Execution Example

The document describes a program that creates two threads - one that prints "Thread1" every 2 seconds and one that prints "Thread2" every 4 seconds. It does this by extending the Thread class to create two instances that override the run method - one prints "Thread1" and sleeps for 2 seconds in a for loop 5 times, the other prints "Thread2" and sleeps for 4 seconds in a for loop 5 times. The main method then starts both threads to run concurrently.

Uploaded by

Rushi Pandav
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

Practical -27

Aim :- Write a program that executes two threads. One thread


displays “Thread1” every 2,000 milliseconds, and the other displays
“Thread2” every 4,000 milliseconds. Create the threads by extending
the Thread class.

class NewThread extends Thread


{
NewThread(String threadname)
{
super(threadname);
}

public void run()


{
if( getName().equals("Thread1")==true)
{
for(int i=1;i<=5;i++)
{
[Link]("Thread1");

try
{
[Link](2000);
}
catch(InterruptedException e)
{
[Link]("Exception Occurred.");
}
}
}
else
{
for(int i=1;i<=5;i++)
{
[Link]("Thread2");

try
{
[Link](4000);
}
catch(InterruptedException e)
{
[Link]("Exception Occurred.");
}
}
}
}
}

public class Example


{
public static void main(String[] args)
{
NewThread t1 = new NewThread("Thread1");
NewThread t2 = new NewThread("Thread2");

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

Output:

Thread1
Thread2
Thread1
Thread2
Thread1
Thread1
Thread2
Thread1
Thread2
Thread2

Common questions

Powered by AI

Extending the Thread class in Java allows each instance of the NewThread class to represent an independent thread of execution. This encapsulates the thread's behavior within the class by overriding the 'run' method, which contains the logic that gets executed when 'start' is called on each thread instance. However, extending Thread instead of implementing Runnable ties the thread's behavior to the class's identity, limiting inheritance only to one parent class, which can be restrictive in more complex applications that benefit from multiple inheritance via interfaces .

To enhance extensibility, decouple the thread behavior from its execution control by implementing the Runnable interface rather than extending the Thread class. Create separate classes or anonymous classes for each task to encapsulate specific sleep durations and behaviors. Utilize a ThreadPoolExecutor to manage and scale additional threads systematically allowing dynamic execution control without altering individual thread logic. Consider using configuration files or factories to determine thread behaviors and sleep durations, thereby enabling easy adjustments or additions. This architecture supports future functionality extensions through minor adjustments to configuration or by adding new task classes .

The sleep intervals in 'Thread1' and 'Thread2' control how often each thread's output is printed, effectively coordinating their execution. 'Thread1' pauses for 2000 milliseconds and 'Thread2' for 4000 milliseconds within their respective loops. Consequently, 'Thread1' outputs twice for each 'Thread2' output, resulting in an interleaved pattern where 'Thread1' appears not just before but in between 'Thread2' outputs: for example, 'Thread1' -> 'Thread2' -> 'Thread1' -> 'Thread1' -> 'Thread2'. This pattern reflects the set consumption rates, creating a staggered execution flow that gives 'Thread1' more frequent activity between 'Thread2's longer pauses .

JVM thread scheduling can significantly influence the interleaving and timing of 'Thread1' and 'Thread2' outputs. The JVM, utilizing either time-slicing or priority/preemptive scheduling, may choose different scheduling orders on each run, affecting the timing and order of outputs. Since 'Thread1' sleeps less frequently, it may execute more outputs between the longer sleeps of 'Thread2', but variability in CPU availability, system load, and any JVM-specific optimization or decisions could alter this expected pattern. This underscores the non-deterministic nature of multi-threaded program execution in JVM and the importance of avoiding assumptions about exact scheduling behavior without explicit synchronization .

Applying design principles such as separation of concerns and encapsulation can improve readability and maintainability. Refactoring thread creation into a separate method or class responsible for thread initialization can simplify the main method logic. Additionally, naming conventions and comments that clarify thread purposes and expected behaviors enhance code clarity. Encapsulating the creation process using factory methods or builders can further improve flexibility when new thread types are required. Implementing standard Java idioms, like using logging frameworks for exceptions, replaces generic print statements, offering more professional and structured debugging tools .

Implementing Runnable instead of extending the Thread class would allow for a more flexible design, where the thread-specific behavior is separated from the thread's management and execution. This change enables a class to implement Runnable while potentially inheriting from another class, since it circumvents the single inheritance restriction of Java. It also encourages decoupling of the task from the thread, as the Runnable interface focuses solely on defining a task (via the 'run' method) and leaves the thread execution context to a Thread object, which can then execute different tasks without modifying the class hierarchy .

Starting 'Thread1' before 'Thread2' as in the program's current main method does not deterministically affect output sequences due to JVM's scheduling nature, but it sets an initial preference. However, given both threads run independently once started, their relative timing generally depends more on their sleep duration than initiation order. 'Thread1' will likely output first because it's started prior; however, output might vary with different JVM executions as thread execution order isn't guaranteed by start order alone. Nevertheless, since 'Thread1' sleeps for shorter periods, its more frequent output can lead the sequence without regard to starting order .

Potential concurrency issues in the provided program could arise from the interruption handling and thread scheduling by the Java Virtual Machine (JVM). Although the threads in this example do not share resources or states that could cause race conditions directly, exceptions like 'InterruptedException' need to be handled properly. Additionally, if there were shared data, synchronization would be necessary to prevent data inconsistencies. Ensuring that the JVM schedules 'Thread1' and 'Thread2' in a manner that maintains the desired output order can be challenging due to the non-deterministic nature of thread scheduling .

The error handling strategy in the provided program primarily consists of a try-catch block that catches 'InterruptedException'. This approach is essential for threads using 'Thread.sleep()', as they can be interrupted before the sleep duration ends. However, the program's current error handling is rudimentary; it merely prints a generic "Exception Occurred" message without providing detailed insights into the cause or implications of the error. A more robust error handling approach would include specific error messages or logging, potentially applying recovery or retry logic, depending on the application's needs and user expectations for robustness in concurrent execution .

The program effectively demonstrates basic thread manipulation concepts vital for new programmers learning Java, such as thread creation, the run-start lifecycle, and utilizing sleep for controlling thread activity. It highlights the mechanics of extending the Thread class and managing exceptions related to 'sleep'. However, it might overlook challenges like synchronization or communication between threads. Including discussions on shared states or providing examples with shared resources could enhance educational depth, preparing students for real-world applications requiring coordination and safeguarding against concurrency issues .

You might also like