From c64e92ea8fd7f73bf0a4bfef928766dcb5603c4b Mon Sep 17 00:00:00 2001 From: Arki Date: Sat, 14 Mar 2026 12:54:35 +0300 Subject: [PATCH 1/7] Kim_A_D queue --- .../tasks/queue/BoundedBlockingQueue.java | 41 +++++++++++++++---- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java b/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java index 5c686cff..c5794f3d 100644 --- a/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java +++ b/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java @@ -1,25 +1,48 @@ package hse.java.lectures.lecture6.tasks.queue; -public class BoundedBlockingQueue { +import java.util.ArrayDeque; +import java.util.Queue; +public class BoundedBlockingQueue { + private final Queue queue = new ArrayDeque<>(); + private final int capacity; public BoundedBlockingQueue(int capacity) { - + if(capacity <= 0){ + throw new IllegalArgumentException("Capacity <= 0 :^("); + } + this.capacity = capacity; } - public void put(T item) { + public synchronized void put(T item) throws InterruptedException{ + if(item == null){ + throw new NullPointerException("not null pls"); + } + while(queue.size() == capacity()){ + wait(); + } + + queue.add(item); + notifyAll(); } - public T take() { - return null; + public synchronized T take() throws InterruptedException{ + while(queue.isEmpty()){ + wait(); + } + + T item = queue.remove(); + notifyAll(); + + return item; } - public int size() { - return 0; + public synchronized int size() { + return queue.size(); } public int capacity() { - return 0; + return capacity; } -} +} \ No newline at end of file From 6976d00ae258b3cfd9350b79e0a944062619a76b Mon Sep 17 00:00:00 2001 From: Arki Date: Mon, 23 Mar 2026 16:16:52 +0300 Subject: [PATCH 2/7] Dau --- .../lesson7/dau/DauServiceImplementation.java | 61 +++++++++ .../lectures/lecture7/DauServiceTest.java | 116 ++++++++++++++++++ .../java/lectures/lecture7/MutableClock.java | 34 +++++ 3 files changed, 211 insertions(+) create mode 100644 src/main/java/hse/java/lectures/lesson7/dau/DauServiceImplementation.java create mode 100644 src/test/java/hse/java/lectures/lecture7/DauServiceTest.java create mode 100644 src/test/java/hse/java/lectures/lecture7/MutableClock.java diff --git a/src/main/java/hse/java/lectures/lesson7/dau/DauServiceImplementation.java b/src/main/java/hse/java/lectures/lesson7/dau/DauServiceImplementation.java new file mode 100644 index 00000000..2264294d --- /dev/null +++ b/src/main/java/hse/java/lectures/lesson7/dau/DauServiceImplementation.java @@ -0,0 +1,61 @@ +package hse.java.lectures.lesson7.dau; + +import java.time.Clock; +import java.time.LocalDate; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class DauServiceImplementation implements DauService { + private final Clock clock; + private volatile LocalDate current; + + private final ConcurrentHashMap> today = new ConcurrentHashMap<>(); + private final ConcurrentHashMap> yesterday = new ConcurrentHashMap<>(); + + public DauServiceImplementation(Clock clock) { + this.clock = clock; + this.current = LocalDate.now(clock); + } + + private void isNextDay() { + LocalDate now = LocalDate.now(clock); + + if (!now.equals(current)) { + synchronized (this) { + if (!now.equals(current)) { + yesterday.clear(); + yesterday.putAll(today); + + today.clear(); + + current = now; + } + } + } + } + + @Override + public void postEvent(Event event) { + isNextDay(); + today.computeIfAbsent(event.authorId(), a -> ConcurrentHashMap.newKeySet()).add(event.userId()); + } + + @Override + public Map getDauStatistics(List authorIds) { + isNextDay(); + + Map result = new HashMap<>(); + + for (Integer authorId : authorIds) { + Set users = yesterday.get(authorId); + result.put(authorId, users == null ? 0L : (long) users.size()); + } + + return result; + } + + @Override + public Long getAuthorDauStatistics(int authorId) { + return getDauStatistics(List.of(authorId)).get(authorId); + } +} \ No newline at end of file diff --git a/src/test/java/hse/java/lectures/lecture7/DauServiceTest.java b/src/test/java/hse/java/lectures/lecture7/DauServiceTest.java new file mode 100644 index 00000000..39ef182a --- /dev/null +++ b/src/test/java/hse/java/lectures/lecture7/DauServiceTest.java @@ -0,0 +1,116 @@ +package hse.java.lectures.lecture7; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import java.time.*; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +import hse.java.lectures.lesson7.dau.*; + +@Tag("Dau") +class DauServiceTest { + + private MutableClock clock; + private DauServiceImplementation service; + + private static final ZoneId ZONE = ZoneOffset.UTC; + + @BeforeEach + void setUp() { + clock = new MutableClock(LocalDate.of(2026, 3, 21).atStartOfDay(ZONE).toInstant(), ZONE); + + service = new DauServiceImplementation(clock); + } + + private void setDate(LocalDate date) { + clock.setInstant(date.atStartOfDay(ZONE).toInstant()); + } + + @Test + void singleUser_singleClick() { + setDate(LocalDate.of(2026, 3, 20)); + service.postEvent(new Event(1, 100)); + + setDate(LocalDate.of(2026, 3, 21)); + + Long result = service.getAuthorDauStatistics(100); + + assertEquals(1L, result); + } + + @Test + void sameUser_multipleClicks() { + setDate(LocalDate.of(2026, 3, 20)); + + service.postEvent(new Event(1, 100)); + service.postEvent(new Event(1, 100)); + service.postEvent(new Event(1, 100)); + + setDate(LocalDate.of(2026, 3, 21)); + + assertEquals(1L, service.getAuthorDauStatistics(100)); + } + + @Test + void multipleUsers() { + setDate(LocalDate.of(2026, 3, 20)); + + service.postEvent(new Event(1, 100)); + service.postEvent(new Event(2, 100)); + service.postEvent(new Event(3, 100)); + + setDate(LocalDate.of(2026, 3, 21)); + + assertEquals(3L, service.getAuthorDauStatistics(100)); + } + + @Test + void differentAuthors() { + setDate(LocalDate.of(2026, 3, 20)); + + service.postEvent(new Event(1, 100)); + service.postEvent(new Event(2, 200)); + + setDate(LocalDate.of(2026, 3, 21)); + + Map stats = service.getDauStatistics(List.of(100, 200)); + + assertEquals(1L, stats.get(100)); + assertEquals(1L, stats.get(200)); + } + + @Test + void emptyClick() { + Map stats = service.getDauStatistics(List.of(100)); + + assertEquals(0L, stats.get(100)); + } + + @Test + void isTodayClicks() { + service.postEvent(new Event(1, 100)); + + assertEquals(0L, service.getAuthorDauStatistics(100)); + } + + @Test + void isDataClear() { + setDate(LocalDate.of(2026, 3, 20)); + service.postEvent(new Event(1, 100)); + + setDate(LocalDate.of(2026, 3, 21)); + service.postEvent(new Event(2, 100)); + + assertEquals(1L, service.getAuthorDauStatistics(100)); + + setDate(LocalDate.of(2026, 3, 22)); + service.postEvent(new Event(3, 100)); + + assertEquals(1L, service.getAuthorDauStatistics(100)); + } +} \ No newline at end of file diff --git a/src/test/java/hse/java/lectures/lecture7/MutableClock.java b/src/test/java/hse/java/lectures/lecture7/MutableClock.java new file mode 100644 index 00000000..9b63db1e --- /dev/null +++ b/src/test/java/hse/java/lectures/lecture7/MutableClock.java @@ -0,0 +1,34 @@ +package hse.java.lectures.lecture7; + +import lombok.Setter; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; + +class MutableClock extends Clock { + + @Setter + private Instant instant; + private final ZoneId zone; + + public MutableClock(Instant instant, ZoneId zone) { + this.instant = instant; + this.zone = zone; + } + + @Override + public ZoneId getZone() { + return zone; + } + + @Override + public Clock withZone(ZoneId zone) { + return new MutableClock(instant, zone); + } + + @Override + public Instant instant() { + return instant; + } +} \ No newline at end of file From cd1c8cc1003d1e540f480c5c7c3e18e0f97145e7 Mon Sep 17 00:00:00 2001 From: Arki Date: Mon, 23 Mar 2026 16:29:34 +0300 Subject: [PATCH 3/7] Dau: test --- .../lecture6/tasks/queue/BoundedBlockingQueue.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java b/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java index 2b5d26cf..5ea204ab 100644 --- a/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java +++ b/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java @@ -4,6 +4,7 @@ import java.util.Queue; public class BoundedBlockingQueue { + private final Queue queue = new ArrayDeque<>(); private final int capacity; @@ -14,14 +15,10 @@ public BoundedBlockingQueue(int capacity) { this.capacity = capacity; } -<<<<<<< HEAD - public void put(T item) throws InterruptedException { -======= public synchronized void put(T item) throws InterruptedException{ if(item == null){ throw new NullPointerException("not null pls"); } ->>>>>>> 1a7546912660f7ad62cf67c9b3a8480d7bfe173b while(queue.size() == capacity()){ wait(); @@ -31,10 +28,6 @@ public synchronized void put(T item) throws InterruptedException{ notifyAll(); } -<<<<<<< HEAD - public T take() throws InterruptedException { - return null; -======= public synchronized T take() throws InterruptedException{ while(queue.isEmpty()){ wait(); @@ -44,7 +37,6 @@ public synchronized T take() throws InterruptedException{ notifyAll(); return item; ->>>>>>> 1a7546912660f7ad62cf67c9b3a8480d7bfe173b } public synchronized int size() { From 60c5d7e0a53166f3c1edbe0316f0a2955fa00db9 Mon Sep 17 00:00:00 2001 From: Arki Date: Mon, 23 Mar 2026 16:30:02 +0300 Subject: [PATCH 4/7] Dau: test --- .../java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java b/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java index 5ea204ab..c5794f3d 100644 --- a/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java +++ b/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java @@ -4,7 +4,6 @@ import java.util.Queue; public class BoundedBlockingQueue { - private final Queue queue = new ArrayDeque<>(); private final int capacity; From fbd350f15721987042156dfd0ae6de3e774fab57 Mon Sep 17 00:00:00 2001 From: Arki Date: Mon, 23 Mar 2026 16:32:58 +0300 Subject: [PATCH 5/7] lol --- .../lesson7/dau/DauServiceImplementation.java | 120 ++++----- .../lectures/lecture7/DauServiceTest.java | 230 +++++++++--------- .../java/lectures/lecture7/MutableClock.java | 66 ++--- 3 files changed, 208 insertions(+), 208 deletions(-) diff --git a/src/main/java/hse/java/lectures/lesson7/dau/DauServiceImplementation.java b/src/main/java/hse/java/lectures/lesson7/dau/DauServiceImplementation.java index 2264294d..198f6668 100644 --- a/src/main/java/hse/java/lectures/lesson7/dau/DauServiceImplementation.java +++ b/src/main/java/hse/java/lectures/lesson7/dau/DauServiceImplementation.java @@ -1,61 +1,61 @@ -package hse.java.lectures.lesson7.dau; - -import java.time.Clock; -import java.time.LocalDate; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -public class DauServiceImplementation implements DauService { - private final Clock clock; - private volatile LocalDate current; - - private final ConcurrentHashMap> today = new ConcurrentHashMap<>(); - private final ConcurrentHashMap> yesterday = new ConcurrentHashMap<>(); - - public DauServiceImplementation(Clock clock) { - this.clock = clock; - this.current = LocalDate.now(clock); - } - - private void isNextDay() { - LocalDate now = LocalDate.now(clock); - - if (!now.equals(current)) { - synchronized (this) { - if (!now.equals(current)) { - yesterday.clear(); - yesterday.putAll(today); - - today.clear(); - - current = now; - } - } - } - } - - @Override - public void postEvent(Event event) { - isNextDay(); - today.computeIfAbsent(event.authorId(), a -> ConcurrentHashMap.newKeySet()).add(event.userId()); - } - - @Override - public Map getDauStatistics(List authorIds) { - isNextDay(); - - Map result = new HashMap<>(); - - for (Integer authorId : authorIds) { - Set users = yesterday.get(authorId); - result.put(authorId, users == null ? 0L : (long) users.size()); - } - - return result; - } - - @Override - public Long getAuthorDauStatistics(int authorId) { - return getDauStatistics(List.of(authorId)).get(authorId); - } +package hse.java.lectures.lesson7.dau; + +import java.time.Clock; +import java.time.LocalDate; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +public class DauServiceImplementation implements DauService { + private final Clock clock; + private volatile LocalDate current; + + private final ConcurrentHashMap> today = new ConcurrentHashMap<>(); + private final ConcurrentHashMap> yesterday = new ConcurrentHashMap<>(); + + public DauServiceImplementation(Clock clock) { + this.clock = clock; + this.current = LocalDate.now(clock); + } + + private void isNextDay() { + LocalDate now = LocalDate.now(clock); + + if (!now.equals(current)) { + synchronized (this) { + if (!now.equals(current)) { + yesterday.clear(); + yesterday.putAll(today); + + today.clear(); + + current = now; + } + } + } + } + + @Override + public void postEvent(Event event) { + isNextDay(); + today.computeIfAbsent(event.authorId(), a -> ConcurrentHashMap.newKeySet()).add(event.userId()); + } + + @Override + public Map getDauStatistics(List authorIds) { + isNextDay(); + + Map result = new HashMap<>(); + + for (Integer authorId : authorIds) { + Set users = yesterday.get(authorId); + result.put(authorId, users == null ? 0L : (long) users.size()); + } + + return result; + } + + @Override + public Long getAuthorDauStatistics(int authorId) { + return getDauStatistics(List.of(authorId)).get(authorId); + } } \ No newline at end of file diff --git a/src/test/java/hse/java/lectures/lecture7/DauServiceTest.java b/src/test/java/hse/java/lectures/lecture7/DauServiceTest.java index 39ef182a..6c6eaac6 100644 --- a/src/test/java/hse/java/lectures/lecture7/DauServiceTest.java +++ b/src/test/java/hse/java/lectures/lecture7/DauServiceTest.java @@ -1,116 +1,116 @@ -package hse.java.lectures.lecture7; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; - -import java.time.*; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; - -import hse.java.lectures.lesson7.dau.*; - -@Tag("Dau") -class DauServiceTest { - - private MutableClock clock; - private DauServiceImplementation service; - - private static final ZoneId ZONE = ZoneOffset.UTC; - - @BeforeEach - void setUp() { - clock = new MutableClock(LocalDate.of(2026, 3, 21).atStartOfDay(ZONE).toInstant(), ZONE); - - service = new DauServiceImplementation(clock); - } - - private void setDate(LocalDate date) { - clock.setInstant(date.atStartOfDay(ZONE).toInstant()); - } - - @Test - void singleUser_singleClick() { - setDate(LocalDate.of(2026, 3, 20)); - service.postEvent(new Event(1, 100)); - - setDate(LocalDate.of(2026, 3, 21)); - - Long result = service.getAuthorDauStatistics(100); - - assertEquals(1L, result); - } - - @Test - void sameUser_multipleClicks() { - setDate(LocalDate.of(2026, 3, 20)); - - service.postEvent(new Event(1, 100)); - service.postEvent(new Event(1, 100)); - service.postEvent(new Event(1, 100)); - - setDate(LocalDate.of(2026, 3, 21)); - - assertEquals(1L, service.getAuthorDauStatistics(100)); - } - - @Test - void multipleUsers() { - setDate(LocalDate.of(2026, 3, 20)); - - service.postEvent(new Event(1, 100)); - service.postEvent(new Event(2, 100)); - service.postEvent(new Event(3, 100)); - - setDate(LocalDate.of(2026, 3, 21)); - - assertEquals(3L, service.getAuthorDauStatistics(100)); - } - - @Test - void differentAuthors() { - setDate(LocalDate.of(2026, 3, 20)); - - service.postEvent(new Event(1, 100)); - service.postEvent(new Event(2, 200)); - - setDate(LocalDate.of(2026, 3, 21)); - - Map stats = service.getDauStatistics(List.of(100, 200)); - - assertEquals(1L, stats.get(100)); - assertEquals(1L, stats.get(200)); - } - - @Test - void emptyClick() { - Map stats = service.getDauStatistics(List.of(100)); - - assertEquals(0L, stats.get(100)); - } - - @Test - void isTodayClicks() { - service.postEvent(new Event(1, 100)); - - assertEquals(0L, service.getAuthorDauStatistics(100)); - } - - @Test - void isDataClear() { - setDate(LocalDate.of(2026, 3, 20)); - service.postEvent(new Event(1, 100)); - - setDate(LocalDate.of(2026, 3, 21)); - service.postEvent(new Event(2, 100)); - - assertEquals(1L, service.getAuthorDauStatistics(100)); - - setDate(LocalDate.of(2026, 3, 22)); - service.postEvent(new Event(3, 100)); - - assertEquals(1L, service.getAuthorDauStatistics(100)); - } +package hse.java.lectures.lecture7; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import java.time.*; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +import hse.java.lectures.lesson7.dau.*; + +@Tag("Dau") +class DauServiceTest { + + private MutableClock clock; + private DauServiceImplementation service; + + private static final ZoneId ZONE = ZoneOffset.UTC; + + @BeforeEach + void setUp() { + clock = new MutableClock(LocalDate.of(2026, 3, 21).atStartOfDay(ZONE).toInstant(), ZONE); + + service = new DauServiceImplementation(clock); + } + + private void setDate(LocalDate date) { + clock.setInstant(date.atStartOfDay(ZONE).toInstant()); + } + + @Test + void singleUser_singleClick() { + setDate(LocalDate.of(2026, 3, 20)); + service.postEvent(new Event(1, 100)); + + setDate(LocalDate.of(2026, 3, 21)); + + Long result = service.getAuthorDauStatistics(100); + + assertEquals(1L, result); + } + + @Test + void sameUser_multipleClicks() { + setDate(LocalDate.of(2026, 3, 20)); + + service.postEvent(new Event(1, 100)); + service.postEvent(new Event(1, 100)); + service.postEvent(new Event(1, 100)); + + setDate(LocalDate.of(2026, 3, 21)); + + assertEquals(1L, service.getAuthorDauStatistics(100)); + } + + @Test + void multipleUsers() { + setDate(LocalDate.of(2026, 3, 20)); + + service.postEvent(new Event(1, 100)); + service.postEvent(new Event(2, 100)); + service.postEvent(new Event(3, 100)); + + setDate(LocalDate.of(2026, 3, 21)); + + assertEquals(3L, service.getAuthorDauStatistics(100)); + } + + @Test + void differentAuthors() { + setDate(LocalDate.of(2026, 3, 20)); + + service.postEvent(new Event(1, 100)); + service.postEvent(new Event(2, 200)); + + setDate(LocalDate.of(2026, 3, 21)); + + Map stats = service.getDauStatistics(List.of(100, 200)); + + assertEquals(1L, stats.get(100)); + assertEquals(1L, stats.get(200)); + } + + @Test + void emptyClick() { + Map stats = service.getDauStatistics(List.of(100)); + + assertEquals(0L, stats.get(100)); + } + + @Test + void isTodayClicks() { + service.postEvent(new Event(1, 100)); + + assertEquals(0L, service.getAuthorDauStatistics(100)); + } + + @Test + void isDataClear() { + setDate(LocalDate.of(2026, 3, 20)); + service.postEvent(new Event(1, 100)); + + setDate(LocalDate.of(2026, 3, 21)); + service.postEvent(new Event(2, 100)); + + assertEquals(1L, service.getAuthorDauStatistics(100)); + + setDate(LocalDate.of(2026, 3, 22)); + service.postEvent(new Event(3, 100)); + + assertEquals(1L, service.getAuthorDauStatistics(100)); + } } \ No newline at end of file diff --git a/src/test/java/hse/java/lectures/lecture7/MutableClock.java b/src/test/java/hse/java/lectures/lecture7/MutableClock.java index 9b63db1e..a2c0d043 100644 --- a/src/test/java/hse/java/lectures/lecture7/MutableClock.java +++ b/src/test/java/hse/java/lectures/lecture7/MutableClock.java @@ -1,34 +1,34 @@ -package hse.java.lectures.lecture7; - -import lombok.Setter; - -import java.time.Clock; -import java.time.Instant; -import java.time.ZoneId; - -class MutableClock extends Clock { - - @Setter - private Instant instant; - private final ZoneId zone; - - public MutableClock(Instant instant, ZoneId zone) { - this.instant = instant; - this.zone = zone; - } - - @Override - public ZoneId getZone() { - return zone; - } - - @Override - public Clock withZone(ZoneId zone) { - return new MutableClock(instant, zone); - } - - @Override - public Instant instant() { - return instant; - } +package hse.java.lectures.lecture7; + +import lombok.Setter; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; + +class MutableClock extends Clock { + + @Setter + private Instant instant; + private final ZoneId zone; + + public MutableClock(Instant instant, ZoneId zone) { + this.instant = instant; + this.zone = zone; + } + + @Override + public ZoneId getZone() { + return zone; + } + + @Override + public Clock withZone(ZoneId zone) { + return new MutableClock(instant, zone); + } + + @Override + public Instant instant() { + return instant; + } } \ No newline at end of file From fff2d90e09e09045eeec65762aa82a24c86eca9c Mon Sep 17 00:00:00 2001 From: Arki Date: Mon, 23 Mar 2026 16:36:47 +0300 Subject: [PATCH 6/7] Dau: test --- src/test/java/hse/java/lectures/lecture7/DauServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/hse/java/lectures/lecture7/DauServiceTest.java b/src/test/java/hse/java/lectures/lecture7/DauServiceTest.java index 6c6eaac6..92a46e48 100644 --- a/src/test/java/hse/java/lectures/lecture7/DauServiceTest.java +++ b/src/test/java/hse/java/lectures/lecture7/DauServiceTest.java @@ -113,4 +113,4 @@ void isDataClear() { assertEquals(1L, service.getAuthorDauStatistics(100)); } -} \ No newline at end of file +} From 25d6cc02c7d8fb94a6fa6fde7ddd6d7f38a26ee4 Mon Sep 17 00:00:00 2001 From: Arki Date: Tue, 24 Mar 2026 03:42:21 +0300 Subject: [PATCH 7/7] synchronizer: test --- .../tasks/synchronizer/StreamWriter.java | 15 ++++-- .../tasks/synchronizer/StreamingMonitor.java | 47 ++++++++++++++++++- .../tasks/synchronizer/Synchronizer.java | 18 ++++--- 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamWriter.java b/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamWriter.java index fedb5e66..0407988d 100644 --- a/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamWriter.java +++ b/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamWriter.java @@ -26,11 +26,18 @@ public void attachMonitor(StreamingMonitor monitor) { @Override public void run() { - // Writer threads are intentionally infinite for the task contract. while (true) { - output.print(message); - onTick.run(); + try { + if (!monitor.streamWait(id)) { + return; + } + output.print(message); + onTick.run(); + monitor.streamComplete(id); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } } } - } diff --git a/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamingMonitor.java b/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamingMonitor.java index 68e8f279..72259d2d 100644 --- a/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamingMonitor.java +++ b/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamingMonitor.java @@ -1,5 +1,50 @@ package hse.java.lectures.lecture6.tasks.synchronizer; public class StreamingMonitor { - // impl your sync here + private int currentWriter = 0; + private final int writersAmount; + private final int[] ticksDone; + private final int ticksPerWriter; + private boolean isFinish = false; + + public StreamingMonitor(int writersAmount, int ticksPerWriter) { + this.writersAmount = writersAmount; + this.ticksPerWriter = ticksPerWriter; + this.ticksDone = new int[writersAmount]; + } + + public synchronized boolean streamWait(int id) throws InterruptedException { + int myIndex = id - 1; + + while (currentWriter != myIndex && !isFinish) { + wait(); + } + + return !isFinish; + } + + public synchronized void streamComplete(int id) { + int myIndex = id - 1; + ticksDone[myIndex]++; + + currentWriter = (currentWriter + 1) % writersAmount; + + int checker = 0; + while (checker < writersAmount && ticksDone[currentWriter] >= ticksPerWriter) { + currentWriter = (currentWriter + 1) % writersAmount; + checker++; + } + + if (checker == writersAmount) { + isFinish = true; + } + + notifyAll(); + } + + public synchronized void synchFinish() throws InterruptedException { + while (!isFinish) { + wait(); + } + } } diff --git a/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/Synchronizer.java b/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/Synchronizer.java index 3cb8aded..fdc2d429 100644 --- a/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/Synchronizer.java +++ b/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/Synchronizer.java @@ -17,17 +17,23 @@ public Synchronizer(List 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 + StreamingMonitor monitor = new StreamingMonitor(tasks.size(), ticksPerWriter); + + 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(); } - } + try { + monitor.synchFinish(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } }