lab 8.
This commit is contained in:
@@ -13,29 +13,33 @@ public class MyCountDownLatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void countDown() {
|
public void countDown() {
|
||||||
synchronized (lock) {
|
synchronized (this.lock) {
|
||||||
if (count <= 0)
|
if (this.count <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
count--;
|
this.count--;
|
||||||
|
|
||||||
if (count == 0) {
|
if (this.count == 0) {
|
||||||
lock.notifyAll();
|
this.lock.notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void await() throws InterruptedException {
|
public void await() throws InterruptedException {
|
||||||
synchronized (lock) {
|
synchronized (this.lock) {
|
||||||
while (count > 0) {
|
while (this.count > 0) {
|
||||||
lock.wait();
|
this.lock.wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean tryAwait() {
|
||||||
|
return this.getCount() <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
synchronized (lock) {
|
synchronized (this.lock) {
|
||||||
return count;
|
return this.count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,48 +8,49 @@ public class MyReentrantLock {
|
|||||||
private Thread owner;
|
private Thread owner;
|
||||||
|
|
||||||
public void lock() throws InterruptedException {
|
public void lock() throws InterruptedException {
|
||||||
synchronized (lock) {
|
synchronized (this.lock) {
|
||||||
Thread current = Thread.currentThread();
|
Thread current = Thread.currentThread();
|
||||||
|
|
||||||
while (isLocked() && current != owner) {
|
while (isLocked() && current != this.owner) {
|
||||||
lock.wait();
|
this.lock.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
counter++;
|
this.counter++;
|
||||||
owner = current;
|
this.owner = current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean tryLock() {
|
public boolean tryLock() {
|
||||||
synchronized (lock) {
|
synchronized (this.lock) {
|
||||||
Thread current = Thread.currentThread();
|
Thread current = Thread.currentThread();
|
||||||
|
|
||||||
if (isLocked() && current != owner) {
|
if (isLocked() && current != this.owner) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
counter++;
|
this.counter++;
|
||||||
owner = current;
|
this.owner = current;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unlock() {
|
public void unlock() {
|
||||||
synchronized (lock) {
|
synchronized (this.lock) {
|
||||||
if (Thread.currentThread() != owner) {
|
if (Thread.currentThread() != this.owner) {
|
||||||
throw new IllegalMonitorStateException("Not owner");
|
throw new IllegalMonitorStateException("Not owner");
|
||||||
}
|
}
|
||||||
|
|
||||||
counter--;
|
this.counter--;
|
||||||
|
|
||||||
if (counter == 0) {
|
if (this.counter == 0) {
|
||||||
owner = null;
|
this.owner = null;
|
||||||
lock.notify();
|
this.lock.notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isLocked() {
|
private boolean isLocked() {
|
||||||
return counter > 0;
|
return this.counter > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,36 +10,37 @@ public class MySemaphore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void acquire() throws InterruptedException {
|
public void acquire() throws InterruptedException {
|
||||||
synchronized (lock) {
|
synchronized (this.lock) {
|
||||||
while (permits <= 0) {
|
while (this.permits <= 0) {
|
||||||
lock.wait();
|
this.lock.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
permits--;
|
this.permits--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean tryAcquire() {
|
public boolean tryAcquire() {
|
||||||
synchronized (lock) {
|
synchronized (this.lock) {
|
||||||
if (permits <= 0) {
|
if (this.permits <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
permits--;
|
this.permits--;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void release() {
|
public void release() {
|
||||||
synchronized (lock) {
|
synchronized (this.lock) {
|
||||||
permits++;
|
this.permits++;
|
||||||
lock.notify();
|
this.lock.notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int availablePermits() {
|
public int availablePermits() {
|
||||||
synchronized (lock) {
|
synchronized (this.lock) {
|
||||||
return permits;
|
return this.permits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import org.junit.jupiter.api.RepeatedTest;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.Timeout;
|
import org.junit.jupiter.api.Timeout;
|
||||||
import ru.lionarius.sync.MyCountDownLatch;
|
import ru.lionarius.sync.MyCountDownLatch;
|
||||||
@@ -30,7 +31,7 @@ class MyCountDownLatchTest {
|
|||||||
assertEquals(0, latch.getCount());
|
assertEquals(0, latch.getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@RepeatedTest(20)
|
||||||
void testAwait() throws InterruptedException {
|
void testAwait() throws InterruptedException {
|
||||||
var latch = new MyCountDownLatch(2);
|
var latch = new MyCountDownLatch(2);
|
||||||
var threadFinished = new AtomicBoolean(false);
|
var threadFinished = new AtomicBoolean(false);
|
||||||
@@ -39,8 +40,7 @@ class MyCountDownLatchTest {
|
|||||||
try {
|
try {
|
||||||
latch.await();
|
latch.await();
|
||||||
threadFinished.set(true);
|
threadFinished.set(true);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException ignored) {
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -58,6 +58,7 @@ class MyCountDownLatchTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Timeout(value = 1000, unit = TimeUnit.MILLISECONDS)
|
||||||
void testMultipleThreads() throws InterruptedException {
|
void testMultipleThreads() throws InterruptedException {
|
||||||
final int THREAD_COUNT = 5;
|
final int THREAD_COUNT = 5;
|
||||||
var startLatch = new MyCountDownLatch(1);
|
var startLatch = new MyCountDownLatch(1);
|
||||||
@@ -76,8 +77,7 @@ class MyCountDownLatchTest {
|
|||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
threadsFinished[index].set(true);
|
threadsFinished[index].set(true);
|
||||||
endLatch.countDown();
|
endLatch.countDown();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException ignored) {
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,6 @@ class MyCountDownLatchTest {
|
|||||||
void testZeroCount() throws InterruptedException {
|
void testZeroCount() throws InterruptedException {
|
||||||
var latch = new MyCountDownLatch(0);
|
var latch = new MyCountDownLatch(0);
|
||||||
assertEquals(0, latch.getCount());
|
assertEquals(0, latch.getCount());
|
||||||
latch.await();
|
assertTrue(latch.tryAwait());
|
||||||
assertTrue(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ class MyReentrantLockTest {
|
|||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUnlock() {
|
||||||
|
assertThrows(IllegalMonitorStateException.class, lock::unlock);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Timeout(value = 1000, unit = TimeUnit.MILLISECONDS)
|
@Timeout(value = 1000, unit = TimeUnit.MILLISECONDS)
|
||||||
void testTryLock() throws InterruptedException {
|
void testTryLock() throws InterruptedException {
|
||||||
@@ -68,11 +73,11 @@ class MyReentrantLockTest {
|
|||||||
threads[i] = new Thread(() -> {
|
threads[i] = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
Thread.sleep(10);
|
|
||||||
lock.unlock();
|
|
||||||
threadsCompleted[index].set(true);
|
threadsCompleted[index].set(true);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException ignored) {
|
||||||
Thread.currentThread().interrupt();
|
}
|
||||||
|
finally {
|
||||||
|
lock.unlock();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
threads[i].start();
|
threads[i].start();
|
||||||
|
|||||||
@@ -46,9 +46,12 @@ class MySemaphoreTest {
|
|||||||
void testMultipleThreads() throws InterruptedException {
|
void testMultipleThreads() throws InterruptedException {
|
||||||
final int THREAD_COUNT = 10;
|
final int THREAD_COUNT = 10;
|
||||||
final int PERMITS = 3;
|
final int PERMITS = 3;
|
||||||
|
|
||||||
var semaphore = new MySemaphore(PERMITS);
|
var semaphore = new MySemaphore(PERMITS);
|
||||||
|
|
||||||
var startLatch = new CountDownLatch(1);
|
var startLatch = new CountDownLatch(1);
|
||||||
var finishLatch = new CountDownLatch(THREAD_COUNT);
|
var finishLatch = new CountDownLatch(THREAD_COUNT);
|
||||||
|
|
||||||
var concurrentThreads = new AtomicInteger(0);
|
var concurrentThreads = new AtomicInteger(0);
|
||||||
var maxConcurrentThreads = new AtomicInteger(0);
|
var maxConcurrentThreads = new AtomicInteger(0);
|
||||||
|
|
||||||
@@ -57,14 +60,17 @@ class MySemaphoreTest {
|
|||||||
try {
|
try {
|
||||||
startLatch.await();
|
startLatch.await();
|
||||||
semaphore.acquire();
|
semaphore.acquire();
|
||||||
|
|
||||||
int current = concurrentThreads.incrementAndGet();
|
int current = concurrentThreads.incrementAndGet();
|
||||||
maxConcurrentThreads.updateAndGet(max -> Math.max(max, current));
|
maxConcurrentThreads.updateAndGet(max -> Math.max(max, current));
|
||||||
Thread.sleep(100); // Имитация работы
|
|
||||||
|
Thread.sleep(100);
|
||||||
|
|
||||||
concurrentThreads.decrementAndGet();
|
concurrentThreads.decrementAndGet();
|
||||||
|
|
||||||
semaphore.release();
|
semaphore.release();
|
||||||
finishLatch.countDown();
|
finishLatch.countDown();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException ignored) {
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
@@ -81,21 +87,28 @@ class MySemaphoreTest {
|
|||||||
semaphore.acquire();
|
semaphore.acquire();
|
||||||
assertEquals(0, semaphore.availablePermits());
|
assertEquals(0, semaphore.availablePermits());
|
||||||
|
|
||||||
|
var startLatch = new CountDownLatch(1);
|
||||||
|
var doneLatch = new CountDownLatch(1);
|
||||||
var thread = new Thread(() -> {
|
var thread = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
|
startLatch.countDown();
|
||||||
|
|
||||||
semaphore.acquire();
|
semaphore.acquire();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException ignored) {
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
doneLatch.countDown();
|
||||||
});
|
});
|
||||||
|
|
||||||
thread.start();
|
thread.start();
|
||||||
Thread.sleep(100); // Даем время потоку начать ожидание
|
startLatch.await();
|
||||||
|
|
||||||
assertTrue(thread.isAlive());
|
assertTrue(thread.isAlive());
|
||||||
assertEquals(0, semaphore.availablePermits());
|
assertEquals(0, semaphore.availablePermits());
|
||||||
|
|
||||||
semaphore.release();
|
semaphore.release();
|
||||||
thread.join(1000);
|
doneLatch.await();
|
||||||
|
|
||||||
assertFalse(thread.isAlive());
|
assertFalse(thread.isAlive());
|
||||||
assertEquals(0, semaphore.availablePermits());
|
assertEquals(0, semaphore.availablePermits());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user