Internal Java Practical Date: 23.03.
2026
Name: Mohit Raj Enrollment No.: 00418002724
Class: CSE 2A, Group: 1 Faculty: Ms. Preeti Pandey
Q 1. Explain the concept of multithreading in Java. Describe how the producer–
consumer problem is solved using threads and synchronization.
Ans. Multithreading is essentially Java's way of doing several things at once. Instead of a
program running in a single, straight line, it splits into multiple "threads" that run concurrently.
This is especially useful for maximizing CPU usage or keeping a user interface responsive while
a heavy file is downloaded in the background.
Core Concepts of Multithreading
In Java, every thread is an instance of the [Link] class or a subclass of it. There are two
primary ways to create one:
1. Extending the Thread class.
2. Implementing the Runnable interface (the preferred method for better flexibility).
When multiple threads access the same data, things can get messy—think of two people trying to
write on the same piece of paper at the exact same time. This is where Synchronization comes
in. Using the synchronized keyword, you can ensure that only one thread accesses a specific
block of code or object at a time.
The Producer–Consumer Problem
The Producer-Consumer problem is a classic multi-process synchronization challenge.
• The Producer: Generates data and places it into a shared buffer (like a queue).
• The Consumer: Takes that data out of the buffer and processes it.
• The Conflict: The producer shouldn't add data if the buffer is full, and the consumer
shouldn't try to take data if the buffer is empty.
How it's Solved with Synchronization
To solve this, Java uses a combination of Locks and Inter-thread Communication (wait() and
notify()).
1. The Shared Buffer: Usually a LinkedList or a specialized BlockingQueue.
2. The Lock: Both threads must synchronize on the buffer object.
3. wait(): If the producer finds the buffer full, it calls wait(). This puts the producer to sleep
and releases the lock so the consumer can get in there and eat some data.
4. notify(): Once the consumer removes an item, it calls notify(). This "pokes" the producer
to wake up and start producing again.
Q2. What are Java packages and interfaces? Explain how dynamic polymorphism
can be implemented using interfaces with a suitable example.
Ans.
1. Java Packages: The Filing Cabinet
A Package is simply a container (a folder) used to group related classes and interfaces.
• Why use them? To avoid naming conflicts. You can have two classes named User,
as long as one is in [Link] and the other is in [Link].
• The Syntax: You declare it at the very top of your file: package [Link];
2. Java Interfaces: The Contract
An Interface is a blueprint of a class. It tells a class what it must do, but not how to do it. It
contains abstract methods (methods without a body).
• The "Contract": When a class implements an interface, it signs a "contract"
promising to provide the logic for all the methods defined in that interface.
• Multiple Inheritance: A class can only inherit from one parent class, but it can
implement multiple interfaces.
3. Dynamic Polymorphism via Interfaces
Dynamic Polymorphism (or Run-time Polymorphism) is the ability of a single interface to
represent different underlying forms at runtime.
In plain English: You write code that talks to the interface, and Java figures out which
specific class to run while the program is actually executing.
The Real-World Example: A Payment System
Imagine an e-commerce app. We don't want to rewrite our "Checkout" code every time we
add a new payment method (PayPal, Stripe, Crypto). Instead, we use an interface.
Step 1: Define the Interface
Java
interface PaymentMethod {
void processPayment(double amount);
}
Step 2: Create Implementation Classes
Java
class CreditCard implements PaymentMethod {
public void processPayment(double amount) {
[Link]("Processing $" + amount + " via Credit Card.");
}
}
class PayPal implements PaymentMethod {
public void processPayment(double amount) {
[Link]("Processing $" + amount + " via PayPal.");
}
}
Step 3: Implementation (The Polymorphism Magic)
Java
public class CheckoutSystem {
public static void main(String[] args) {
// The reference type is the INTERFACE, but the object is a specific CLASS
PaymentMethod myPayment;
// At runtime, we can swap the logic
myPayment = new CreditCard();
[Link](100.0); // Output: Processing via Credit Card
myPayment = new PayPal();
[Link](250.0); // Output: Processing via PayPal
}
}
Why is this "Dynamic"?
The compiler only knows that myPayment is a PaymentMethod. It doesn't know (or care)
whether it's a Credit Card or PayPal until the code is actually running. This makes your
code incredibly flexible—you can add a CryptoPayment class later without changing a
single line of your CheckoutSystem logic.
Q 3. Write a Java program to implement Stack and Queue operations (push, pop,
enqueue, dequeue) using appropriate data structures.
Ans. import [Link];
public class DataStructureDemo {
public static void main(String[] args) {
// --- STACK OPERATIONS (LIFO: Last-In, First-Out) ---
LinkedList<String> stack = new LinkedList<>();
[Link]("--- Stack Operations ---");
[Link]("Plate 1");
[Link]("Plate 2");
[Link]("Plate 3");
[Link]("Stack after pushes: " + stack);
String poppedItem = [Link](); // Removes "Plate 3"
[Link]("Popped item: " + poppedItem);
[Link]("Stack after pop: " + stack);
// --- QUEUE OPERATIONS (FIFO: First-In, First-Out) ---
LinkedList<String> queue = new LinkedList<>();
[Link]("\n--- Queue Operations ---");
[Link]("Customer A"); // Enqueue
[Link]("Customer B");
[Link]("Customer C");
[Link]("Queue after enqueuing: " + queue);
String dequeuedItem = [Link](); // Dequeue (removes "Customer A")
[Link]("Dequeued item: " + dequeuedItem);
[Link]("Queue after dequeue: " + queue);
}
}
Q 4. Write a Java program that reads the content of a text file and converts all
characters into uppercase, then saves the modified content back into the file .
Ans. import [Link];
import [Link];
import [Link];
import [Link];
public class FileUppercaseConverter {
public static void main(String[] args) {
// Specify the path to your text file
Path filePath = [Link]("[Link]");
try {
// 1. Read all content from the file into a String
// Note: This works best for standard text files.
// For massive gigabyte-sized files, we'd use a different 'stream' approach.
String content = [Link](filePath);
// 2. Convert the string to uppercase
String upperContent = [Link]();
// 3. Write the modified content back to the same file
// This will overwrite the existing content.
[Link](filePath, upperContent);
[Link]("Success! The file has been shouted (converted to
uppercase).");
} catch (IOException e) {
[Link]("Error: Could not process the file. " + [Link]());
}
}
}