Skip to content

Commit

Permalink
Done homework 7
Browse files Browse the repository at this point in the history
  • Loading branch information
arhostcode committed Nov 23, 2023
1 parent 3ea530a commit 37b2bc9
Show file tree
Hide file tree
Showing 12 changed files with 406 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/main/java/edu/hw7/task1/MultiCounter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package edu.hw7.task1;

import java.util.concurrent.atomic.AtomicInteger;

public class MultiCounter {

private final AtomicInteger counter;

public MultiCounter() {
counter = new AtomicInteger(0);
}

public void increment() {
counter.incrementAndGet();
}

public int get() {
return counter.get();
}
}
16 changes: 16 additions & 0 deletions src/main/java/edu/hw7/task2/ParallelFactorial.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package edu.hw7.task2;

import java.util.stream.IntStream;

public final class ParallelFactorial {

private ParallelFactorial() {
}

public static int computeFactorial(int n) {
return IntStream.rangeClosed(1, n)
.parallel()
.reduce((i1, i2) -> i1 * i2)
.orElseThrow();
}
}
64 changes: 64 additions & 0 deletions src/main/java/edu/hw7/task3/AbstractPersonDatabase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package edu.hw7.task3;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.SneakyThrows;
import org.jetbrains.annotations.Nullable;

public class AbstractPersonDatabase implements PersonDatabase {

private final Map<Integer, Person> cachedIds = new HashMap<>();
private final Map<String, List<Person>> cachedNames = new HashMap<>();
private final Map<String, List<Person>> cachedAddresses = new HashMap<>();
private final Map<String, List<Person>> cachedPhones = new HashMap<>();

@SneakyThrows
@Override
public void add(Person person) {
cachedIds.put(person.id(), person);
cachedNames.computeIfAbsent(person.name(), name -> new ArrayList<>()).add(person);
cachedAddresses.computeIfAbsent(person.address(), name -> new ArrayList<>()).add(person);
cachedPhones.computeIfAbsent(person.phoneNumber(), name -> new ArrayList<>()).add(person);
}

@Override
public void delete(int id) {
Person removed = cachedIds.remove(id);
if (removed == null) {
return;
}
cachedNames.remove(removed.name());
cachedAddresses.remove(removed.address());
cachedPhones.remove(removed.phoneNumber());
}

@Override
@Nullable
public List<Person> findByName(String name) {
if (!cachedNames.containsKey(name)) {
return null;
}
return cachedNames.get(name).stream().toList();
}

@Override
@Nullable
public List<Person> findByAddress(String address) {
if (!cachedAddresses.containsKey(address)) {
return null;
}
return cachedAddresses.get(address).stream().toList();
}

@Override
@Nullable
public List<Person> findByPhone(String phone) {
if (!cachedPhones.containsKey(phone)) {
return null;
}
return cachedPhones.get(phone).stream().toList();
}

}
37 changes: 37 additions & 0 deletions src/main/java/edu/hw7/task3/CachingPersonDatabase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package edu.hw7.task3;

import java.util.List;
import lombok.SneakyThrows;
import org.jetbrains.annotations.Nullable;

public class CachingPersonDatabase extends AbstractPersonDatabase {

@SneakyThrows
@Override
public synchronized void add(Person person) {
super.add(person);
}

@Override
public synchronized void delete(int id) {
super.delete(id);
}

@Override
@Nullable
public synchronized List<Person> findByName(String name) {
return super.findByName(name);
}

@Override
@Nullable
public synchronized List<Person> findByAddress(String address) {
return super.findByAddress(address);
}

@Override
@Nullable
public synchronized List<Person> findByPhone(String phone) {
return super.findByPhone(phone);
}
}
66 changes: 66 additions & 0 deletions src/main/java/edu/hw7/task3/LockCachingPersonDatabase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package edu.hw7.task3;

import java.util.List;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import lombok.SneakyThrows;
import org.jetbrains.annotations.Nullable;

public class LockCachingPersonDatabase extends AbstractPersonDatabase {

private final ReadWriteLock lock = new ReentrantReadWriteLock();

@SneakyThrows
@Override
public void add(Person person) {
try {
lock.writeLock().lock();
super.add(person);
} finally {
lock.writeLock().unlock();
}
}

@Override
public void delete(int id) {
try {
lock.writeLock().lock();
super.delete(id);
} finally {
lock.writeLock().unlock();
}
}

@Override
@Nullable
public List<Person> findByName(String name) {
try {
lock.readLock().lock();
return super.findByName(name);
} finally {
lock.readLock().unlock();
}
}

@Override
@Nullable
public List<Person> findByAddress(String address) {
try {
lock.readLock().lock();
return super.findByAddress(address);
} finally {
lock.readLock().unlock();
}
}

@Override
@Nullable
public List<Person> findByPhone(String phone) {
try {
lock.readLock().lock();
return super.findByPhone(phone);
} finally {
lock.readLock().unlock();
}
}
}
4 changes: 4 additions & 0 deletions src/main/java/edu/hw7/task3/Person.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package edu.hw7.task3;

public record Person(int id, String name, String address, String phoneNumber) {
}
18 changes: 18 additions & 0 deletions src/main/java/edu/hw7/task3/PersonDatabase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package edu.hw7.task3;

import java.util.List;
import org.jetbrains.annotations.Nullable;

public interface PersonDatabase {
void add(Person person);

void delete(int id);

@Nullable List<Person> findByName(String name);

@Nullable
List<Person> findByAddress(String address);

@Nullable
List<Person> findByPhone(String phone);
}
60 changes: 60 additions & 0 deletions src/main/java/edu/hw7/task4/MonteCarloPiComputer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package edu.hw7.task4;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadLocalRandom;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;

@UtilityClass
public class MonteCarloPiComputer {

private static final double MONTE_CARLO_CONST = 4.0;
private static final double RADIUS = 0.5;

public static double computePI(long iterationsCount) {
double result = countRandomCollisions(iterationsCount);
return MONTE_CARLO_CONST * (result / iterationsCount);
}

@SneakyThrows
public static double computePIParallel(long n, int threadCount) {
var executorService = Executors.newFixedThreadPool(threadCount);
double count = 0;

// Not using atomics here to speed up the process
Future<Long>[] futures = new Future[threadCount];
CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int thread = 0; thread < threadCount; thread++) {
futures[thread] = executorService.submit(() -> {
long countInThread = countRandomCollisions(n / threadCount);
countDownLatch.countDown();
return countInThread;
});
}
countDownLatch.await();
for (int i = 0; i < threadCount; i++) {
count += futures[i].get();
}
return MONTE_CARLO_CONST * (count / n);
}

private long countRandomCollisions(long iterationsCount) {
long count = 0;
Random random = ThreadLocalRandom.current();
for (long i = 0; i < iterationsCount; i++) {
double x = random.nextDouble();
double y = random.nextDouble();
if (isInSingleCircle(x, y)) {
count++;
}
}
return count;
}

private static boolean isInSingleCircle(double x, double y) {
return (x - RADIUS) * (x - RADIUS) + (y - RADIUS) * (y - RADIUS) <= RADIUS * RADIUS;
}
}
31 changes: 31 additions & 0 deletions src/test/java/edu/hw7/task1/MultiCounterTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package edu.hw7.task1;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import lombok.SneakyThrows;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class MultiCounterTest {

@SneakyThrows
@Test
@DisplayName("Тестирование MultiCounter#get и MultiCounter#increment")
public void get_shouldReturnCorrectInt_whenIncremented() {
final int threadCount = 5;
var executorService = Executors.newFixedThreadPool(threadCount);
var countDownLatch = new CountDownLatch(threadCount);
var counter = new MultiCounter();
for (int i = 0; i < threadCount; i++) {
executorService.submit(() -> {
for (int j = 0; j < 1000; j++) {
counter.increment();
}
countDownLatch.countDown();
});
}
countDownLatch.await();
Assertions.assertThat(counter.get()).isEqualTo(threadCount * 1000);
}
}
14 changes: 14 additions & 0 deletions src/test/java/edu/hw7/task2/ParallelFactorialTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package edu.hw7.task2;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class ParallelFactorialTest {

@Test
@DisplayName("Тестирование ParallelFactorial#computeFactorial")
public void computeFactorial_shouldReturnCorrectInt() {
Assertions.assertThat(ParallelFactorial.computeFactorial(5)).isEqualTo(120);
}
}
52 changes: 52 additions & 0 deletions src/test/java/edu/hw7/task3/PersonDatabaseTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package edu.hw7.task3;

import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import lombok.SneakyThrows;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertAll;

public class PersonDatabaseTest {

@Test
@DisplayName("Тестирование LockCachingPersonDatabase")
public void lockDatabase_shouldReturnCorrectPerson_whenPersonAdded() {
PersonDatabase personDatabase = new LockCachingPersonDatabase();
testDatabase(personDatabase);
}

@Test
@DisplayName("Тестирование CachingPersonDatabase")
public void synchronizedDatabase_shouldReturnCorrectPerson_whenPersonAdded() {
PersonDatabase personDatabase = new CachingPersonDatabase() {
@SneakyThrows
@Override
public synchronized void add(Person person) {
Thread.sleep(3000); // Imitation of slow database
super.add(person);
}
};
testDatabase(personDatabase);
}

@SneakyThrows
private static void testDatabase(PersonDatabase personDatabase) {
var executorService = Executors.newFixedThreadPool(5);
var person = new Person(1, "Ivan", "Moscow", "1234567890");
executorService.execute(() -> personDatabase.add(person));
Thread.sleep(100);
Future<List<Person>> futureByPhone = executorService.submit(() -> personDatabase.findByPhone("1234567890"));
Future<List<Person>> futureByName = executorService.submit(() -> personDatabase.findByName("Ivan"));
Future<List<Person>> futureByAddress = executorService.submit(() -> personDatabase.findByAddress("Moscow"));
executorService.shutdown();
assertAll(
() -> Assertions.assertThat(futureByPhone.get()).contains(person),
() -> Assertions.assertThat(futureByName.get()).contains(person),
() -> Assertions.assertThat(futureByAddress.get()).contains(person)
);
}

}
Loading

0 comments on commit 37b2bc9

Please sign in to comment.