Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,25 +1,46 @@
package hse.java.lectures.lecture6.tasks.queue;

import java.util.LinkedList;
import java.util.Queue;

public class BoundedBlockingQueue<T> {

private final int capacity;
private final Queue<T> queue;

public BoundedBlockingQueue(int capacity) {

if (capacity <= 0) {
throw new IllegalArgumentException();
}
this.capacity = capacity;
this.queue = new LinkedList<>();
}

public void put(T item) throws InterruptedException {

public synchronized void put(T item) throws InterruptedException {
if (item == null) {
throw new NullPointerException();
}
while (queue.size() == capacity) {
wait();
}
queue.add(item);
notifyAll();
}

public T take() throws InterruptedException {
return null;
public synchronized T take() throws InterruptedException {
while (queue.isEmpty()) {
wait();
}
T item = queue.poll();
notifyAll();
return item;
}

public int size() {
return 0;
public synchronized int size() {
return queue.size();
}

public int capacity() {
return 0;
return capacity;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ public void attachMonitor(StreamingMonitor monitor) {

@Override
public void run() {
// Writer threads are intentionally infinite for the task contract.
while (true) {
if (!monitor.waitTurn(id)) {
break;
}
Comment on lines 29 to +32
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current implementation exits the writer thread once waitTurn() returns false. This conflicts with the task contract in task.md that describes StreamWriter.run() as an infinite loop; a safer approach is usually to keep the thread alive but block it after completion (or otherwise align the contract + implementation).

Copilot uses AI. Check for mistakes.
output.print(message);
onTick.run();
monitor.tickDone();
Comment on lines 33 to +35
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If output.print(...) or (more likely) onTick.run() throws a runtime exception, tickDone() will never be called and all other writers (and execute() via awaitDone()) can block indefinitely. Call monitor.tickDone() in a finally block, and consider how to handle the exception (e.g., propagate via a shared error flag and unblock waiters).

Suggested change
output.print(message);
onTick.run();
monitor.tickDone();
try {
output.print(message);
onTick.run();
} finally {
monitor.tickDone();
}

Copilot uses AI. Check for mistakes.
}
}

}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
package hse.java.lectures.lecture6.tasks.synchronizer;

public class StreamingMonitor {
// impl your sync here
}

private final int[] sortedIds;
private final int targetTicks;
private int currentIdx = 0;
private int completedTicks = 0;

public StreamingMonitor(int[] sortedIds, int targetTicks) {
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sortedIds is used as sortedIds[currentIdx] in waitTurn(), but the constructor doesn't guard against sortedIds.length == 0, which would cause an ArrayIndexOutOfBoundsException or a hang depending on call path. Consider validating sortedIds (non-null, non-empty) and targetTicks (>= 0) in the constructor and throwing an IllegalArgumentException with a helpful message.

Suggested change
public StreamingMonitor(int[] sortedIds, int targetTicks) {
public StreamingMonitor(int[] sortedIds, int targetTicks) {
if (sortedIds == null || sortedIds.length == 0) {
throw new IllegalArgumentException("sortedIds must be non-null and non-empty");
}
if (targetTicks < 0) {
throw new IllegalArgumentException("targetTicks must be non-negative");
}

Copilot uses AI. Check for mistakes.
this.sortedIds = sortedIds;
this.targetTicks = targetTicks;
}

public synchronized boolean waitTurn(int id) {
try {
while (completedTicks < targetTicks && sortedIds[currentIdx] != id) {
wait();
}
return completedTicks < targetTicks;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}

public synchronized void tickDone() {
currentIdx++;
if (currentIdx == sortedIds.length) {
currentIdx = 0;
completedTicks++;
}
notifyAll();
}

public synchronized void awaitDone() {
try {
while (completedTicks < targetTicks) {
wait();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,24 @@ public Synchronizer(List<StreamWriter> tasks, int ticksPerWriter) {
this.ticksPerWriter = ticksPerWriter;
}

/**
* Starts infinite writer threads and waits until each writer prints exactly ticksPerWriter ticks
* in strict ascending id order.
*/
public void execute() {
// add monitor and sync
int[] sortedIds = tasks.stream()
.mapToInt(StreamWriter::getId)
.sorted()
.toArray();

StreamingMonitor monitor = new StreamingMonitor(sortedIds, ticksPerWriter);

Comment on lines +21 to +27
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

execute() can deadlock when tasks is empty (no worker will ever call tickDone(), so awaitDone() waits forever). Add explicit argument validation (e.g., require tasks.size() >= 1/2 per task contract and ticksPerWriter >= 0) and fail fast with a clear exception before constructing the monitor.

Copilot uses AI. Check for mistakes.
for (StreamWriter writer : tasks) {
writer.attachMonitor(monitor);
}

for (StreamWriter writer : tasks) {
Thread worker = new Thread(writer, "stream-writer-" + writer.getId());
worker.setDaemon(true);
worker.start();
}
}

}
monitor.awaitDone();
}
}
Loading