0% found this document useful (0 votes)
3 views

Question 2 java answers alternative

The document discusses inter-thread communication in Java, focusing on synchronization mechanisms like locks, conditions, and blocking queues. It outlines the implementation of a ReaderWriter pattern using a bounded buffer with a thread pool for reader and writer tasks, employing ReentrantLock and Condition objects for thread coordination. Key features include thread safety, efficient thread management through ExecutorService, and graceful handling of interruptions.

Uploaded by

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

Question 2 java answers alternative

The document discusses inter-thread communication in Java, focusing on synchronization mechanisms like locks, conditions, and blocking queues. It outlines the implementation of a ReaderWriter pattern using a bounded buffer with a thread pool for reader and writer tasks, employing ReentrantLock and Condition objects for thread coordination. Key features include thread safety, efficient thread management through ExecutorService, and graceful handling of interruptions.

Uploaded by

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

(a) Inter-thread Communication in Java

Inter-thread communication in Java involves synchronization mechanisms


that allow threads to coordinate their actions. Key concepts and mechanisms
include:
1. Locks and Conditions:

o ReentrantLock and its associated Condition objects


(Condition.await() and Condition.signal()) are commonly used
to manage more fine-grained thread communication.
2. Synchronized Blocks and Methods:

o Using synchronized ensures mutual exclusion, and the wait(),


notify(), and notifyAll() methods enable threads to wait for
and signal specific conditions.
3. Blocking Queues:

o Classes like ArrayBlockingQueue or LinkedBlockingQueue simplify


producer-consumer implementations by internally managing
locking and conditions.

(b) ReaderWriter Implementation


We’ll implement the requested functionality in a structured manner:
i. Buffer with Limited Size
The buffer will be implemented as a LinkedList<Integer> with a fixed
capacity.
ii. Thread Pool for Reader and Writer Tasks
We’ll use ExecutorService to create a thread pool for running ReaderTask and
WriterTask.

iii. WriterTask Class


The WriterTask class will implement Runnable to add integers to the buffer.
iv. ReaderTask Class
The ReaderTask class will implement Runnable to remove and read integers
from the buffer.
v. Lock and Conditions
We’ll use a ReentrantLock to create explicit locks and Condition objects
(NotFull and NotEmpty) for managing buffer interactions.
vi. Write Method
The write method will acquire the lock, wait if the buffer is full, add an
integer to the buffer, and signal the NotEmpty condition.
vii. Read Method
The read method will acquire the lock, wait if the buffer is empty, remove an
integer from the buffer, and signal the NotFull condition.

Here’s the complete implementation in Java:


import java.util.LinkedList;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;

public class ReaderWriter {


private static final int BUFFER_CAPACITY = 5;
private static final Buffer buffer = new Buffer(BUFFER_CAPACITY);

public static void main(String[] args) {


// Create a thread pool
ExecutorService executor = Executors.newFixedThreadPool(2);

// Execute ReaderTask and WriterTask


executor.execute(new WriterTask(buffer));
executor.execute(new ReaderTask(buffer));

// Shutdown the executor after tasks complete


executor.shutdown();
}

// Buffer class with locking and condition variables


static class Buffer {
private final LinkedList<Integer> buffer = new LinkedList<>();
private final int capacity;

private final Lock lock = new ReentrantLock();


private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();

public Buffer(int capacity) {


this.capacity = capacity;
}
public void write(int value) {
lock.lock();
try {
while (buffer.size() == capacity) {
System.out.println("Buffer is full. Writer is
waiting...");
notFull.await();
}
buffer.add(value);
System.out.println("Writer added: " + value);
notEmpty.signal();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Writer interrupted.");
} finally {
lock.unlock();
}
}

public int read() {


lock.lock();
try {
while (buffer.isEmpty()) {
System.out.println("Buffer is empty. Reader is
waiting...");
notEmpty.await();
}
int value = buffer.removeFirst();
System.out.println("Reader removed: " + value);
notFull.signal();
return value;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Reader interrupted.");
return -1; // Return an invalid value on interruption
} finally {
lock.unlock();
}
}
}

// WriterTask to add integers to the buffer


static class WriterTask implements Runnable {
private final Buffer buffer;

public WriterTask(Buffer buffer) {


this.buffer = buffer;
}
@Override
public void run() {
int value = 1;
while (true) {
buffer.write(value++);
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("WriterTask interrupted.");
break;
}
}
}
}

// ReaderTask to remove and read integers from the buffer


static class ReaderTask implements Runnable {
private final Buffer buffer;

public ReaderTask(Buffer buffer) {


this.buffer = buffer;
}

@Override
public void run() {
while (true) {
buffer.read();
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("ReaderTask interrupted.");
break;
}
}
}
}
}

Key Features:
1. Thread Safety:

o Locking ensures only one thread modifies the buffer at a time.

o Condition variables prevent busy-waiting.

2. Thread Pool:
o ExecutorService manages the threads, ensuring efficient
execution.
3. Graceful Handling:

o Interruptions are handled to allow tasks to exit cleanly if


interrupted.

You might also like