diff --git a/src/main/java/com/thread/concurrency/counter/AtomicCounter.java b/src/main/java/com/thread/concurrency/counter/AtomicCounter.java new file mode 100644 index 0000000..1fdf3bd --- /dev/null +++ b/src/main/java/com/thread/concurrency/counter/AtomicCounter.java @@ -0,0 +1,18 @@ +package com.thread.concurrency.counter; + +import org.springframework.stereotype.Component; + +import java.util.concurrent.atomic.AtomicInteger; + +@Component +public class AtomicCounter implements Counter{ + private final AtomicInteger count = new AtomicInteger(100); + @Override + public void add(int value) { + count.addAndGet(value); + } + @Override + public int show() { + return count.get(); + } +} diff --git a/src/main/java/com/thread/concurrency/counter/CompletableFutureCounter.java b/src/main/java/com/thread/concurrency/counter/CompletableFutureCounter.java new file mode 100644 index 0000000..00e97bb --- /dev/null +++ b/src/main/java/com/thread/concurrency/counter/CompletableFutureCounter.java @@ -0,0 +1,29 @@ +package com.thread.concurrency.counter; + +import org.springframework.stereotype.Component; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +@Component +public class CompletableFutureCounter implements Counter{ + + private CompletableFuture counter; + public CompletableFutureCounter(){ + this.counter = new CompletableFuture<>(); + counter.complete(100); + } + @Override + public void add(int value) { + synchronized (this){ + counter = counter.thenApply((c) -> c + value); + } + } + @Override + public int show() { + try { + return counter.get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/thread/concurrency/counter/SynchronizedCounter.java b/src/main/java/com/thread/concurrency/counter/SynchronizedCounter.java new file mode 100644 index 0000000..aa70b45 --- /dev/null +++ b/src/main/java/com/thread/concurrency/counter/SynchronizedCounter.java @@ -0,0 +1,19 @@ +package com.thread.concurrency.counter; + +import org.springframework.stereotype.Component; + +@Component +public class SynchronizedCounter implements Counter{ + + private int counter = 100; + + @Override + public synchronized void add(int value) { + counter += value; + } + + @Override + public synchronized int show() { + return counter; + } +} diff --git a/src/test/java/com/thread/concurrency/AtomicCounterTest.java b/src/test/java/com/thread/concurrency/AtomicCounterTest.java new file mode 100644 index 0000000..d104356 --- /dev/null +++ b/src/test/java/com/thread/concurrency/AtomicCounterTest.java @@ -0,0 +1,49 @@ +package com.thread.concurrency; + +import com.thread.concurrency.counter.AtomicCounter; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.time.Duration; +import java.time.LocalTime; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@SpringBootTest +public class AtomicCounterTest { + private final int counteNumber = 1; + private final int totalCount = 5000000; + private final int maxThreadNumber = 15; + private static final Logger logger = LoggerFactory.getLogger(SynchronizedCounterTest.class); + @Autowired + AtomicCounter counter; + + @Test + @DisplayName("synchronized로 스레드 안전한 카운터로 동시에 여러 더하기 수행하기.") + public void 여러_더하기_수행_Executor() throws InterruptedException { + + LocalTime lt1 = LocalTime.now(); + int initalCount = counter.show(); + + ExecutorService service = Executors.newFixedThreadPool(maxThreadNumber); + CountDownLatch latch = new CountDownLatch(totalCount); + for (int i = 0; i < totalCount; i++) { + service.submit(() -> { + counter.add(counteNumber); + latch.countDown(); + }); + } + latch.await(); + int finalCount = counter.show(); + LocalTime lt2 = LocalTime.now(); + long dif = Duration.between(lt1, lt2).getNano(); + logger.info("여러_더하기_수행_Executor 테스트가 걸린 시간 : " + ((float)dif / 1000000) + "ms"); + Assertions.assertEquals(initalCount + totalCount * counteNumber, finalCount); + } +} diff --git a/src/test/java/com/thread/concurrency/CompletableFutureCounterTest.java b/src/test/java/com/thread/concurrency/CompletableFutureCounterTest.java new file mode 100644 index 0000000..3999676 --- /dev/null +++ b/src/test/java/com/thread/concurrency/CompletableFutureCounterTest.java @@ -0,0 +1,51 @@ +package com.thread.concurrency; + +import com.thread.concurrency.counter.CompletableFutureCounter; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.time.Duration; +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.*; + +@SpringBootTest +public class CompletableFutureCounterTest { + + private final int counteNumber = 1; + private final int totalCount = 5000; + private final int maxThreadNumber = 15; + private static final Logger logger = LoggerFactory.getLogger(CompletableFutureCounterTest.class); + + @Autowired + CompletableFutureCounter counter; + @Test + @DisplayName("CompletableFuture로 스레드 안전한 카운터로 동시에 여러 더하기 수행하기.") + public void 여러_더하기_수행_Executor() throws InterruptedException { + LocalTime lt1 = LocalTime.now(); + int initalCount = counter.show(); + + ExecutorService service = Executors.newFixedThreadPool(maxThreadNumber); + CountDownLatch latch = new CountDownLatch(totalCount); + for (int i = 0; i < totalCount; i++) { + service.submit(() -> { + counter.add(counteNumber); + latch.countDown(); + }); + } + latch.await(); + int finalCount = counter.show(); + LocalTime lt2 = LocalTime.now(); + long dif = Duration.between(lt1, lt2).getNano(); + logger.info("여러_더하기_수행_Executor 테스트가 걸린 시간 : " + ((float)dif / 1000000) + "ms"); + Assertions.assertEquals(initalCount + totalCount * counteNumber, finalCount); + } +} diff --git a/src/test/java/com/thread/concurrency/SynchronizedCounterTest.java b/src/test/java/com/thread/concurrency/SynchronizedCounterTest.java new file mode 100644 index 0000000..7b073b5 --- /dev/null +++ b/src/test/java/com/thread/concurrency/SynchronizedCounterTest.java @@ -0,0 +1,51 @@ +package com.thread.concurrency; + +import com.thread.concurrency.counter.SynchronizedCounter; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.time.Duration; +import java.time.LocalTime; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@SpringBootTest +public class SynchronizedCounterTest { + + private final int counteNumber = 1; + private final int totalCount = 5000000; + private final int maxThreadNumber = 15; + private static final Logger logger = LoggerFactory.getLogger(SynchronizedCounterTest.class); + + @Autowired + SynchronizedCounter counter; + + @Test + @DisplayName("synchronized로 스레드 안전한 카운터로 동시에 여러 더하기 수행하기.") + public void 여러_더하기_수행_Executor() throws InterruptedException { + + LocalTime lt1 = LocalTime.now(); + int initalCount = counter.show(); + + ExecutorService service = Executors.newFixedThreadPool(maxThreadNumber); + CountDownLatch latch = new CountDownLatch(totalCount); + for (int i = 0; i < totalCount; i++) { + service.submit(() -> { + counter.add(counteNumber); + latch.countDown(); + }); + } + latch.await(); + int finalCount = counter.show(); + LocalTime lt2 = LocalTime.now(); + long dif = Duration.between(lt1, lt2).getNano(); + logger.info("여러_더하기_수행_Executor 테스트가 걸린 시간 : " + ((float)dif / 1000000) + "ms"); + Assertions.assertEquals(initalCount + totalCount * counteNumber, finalCount); + } +}