-
java에서의 동시성 이슈 제어방법자바웹프로그래밍/JAVA 2024. 7. 10. 16:55728x90반응형
1.synchronized 키워드 사용
2.Lock API 사용 (ReentrantLock 등)
3.volatile 키워드 사용
4.Atomic Classes (AtomicInteger, AtomicBoolean 등)
5.Concurrent Collections (예: ConcurrentHashMap, CopyOnWriteArrayList 등)
6.Executor Service와 Future 사용
1. synchronized 키워드 사용
synchronized 키워드는 메서드 또는 블록 수준에서 동기화를 제공합니다. 특정 코드 블록에 동시에 하나의 스레드만 접근하도록 합니다.
class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } } public class SynchronizedExample { public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); Runnable task = () -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println("Final count: " + counter.getCount()); } }
2. Lock API 사용 (ReentrantLock 등)
ReentrantLock은 보다 세밀한 동기화 제어를 제공합니다. lock()과 unlock() 메서드를 명시적으로 호출해야 합니다.
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class Counter { private int count = 0; private Lock lock = new ReentrantLock(); public void increment() { lock.lock(); try { count++; } finally { lock.unlock(); } } public int getCount() { lock.lock(); try { return count; } finally { lock.unlock(); } } } public class ReentrantLockExample { public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); Runnable task = () -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println("Final count: " + counter.getCount()); } }
3. volatile 키워드 사용
volatile 키워드는 변수의 값이 스레드 간에 일관되도록 보장합니다. 주로 읽기 전용 상태를 반영하기 위해 사용됩니다.
class VolatileExample { private volatile boolean running = true; public void stop() { running = false; } public void run() { while (running) { // 작업 수행 } System.out.println("Stopped"); } public static void main(String[] args) throws InterruptedException { VolatileExample example = new VolatileExample(); Thread thread = new Thread(example::run); thread.start(); Thread.sleep(1000); example.stop(); } }
4. Atomic Classes (AtomicInteger, AtomicBoolean 등)
Atomic 클래스는 lock-free 알고리즘을 사용하여 동기화 없이 안전하게 값을 업데이트할 수 있습니다.
import java.util.concurrent.atomic.AtomicInteger; class AtomicCounter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } } public class AtomicExample { public static void main(String[] args) throws InterruptedException { AtomicCounter counter = new AtomicCounter(); Runnable task = () -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println("Final count: " + counter.getCount()); } }
5. Concurrent Collections
Concurrent Collections은 동시성을 위해 설계된 컬렉션으로, 동시 접근 시에도 안전하게 사용할 수 있습니다.
import java.util.concurrent.ConcurrentHashMap; public class ConcurrentHashMapExample { public static void main(String[] args) throws InterruptedException { ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); Runnable task = () -> { for (int i = 0; i < 1000; i++) { map.put("key" + i, i); } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println("Map size: " + map.size()); } }
6. Executor Service와 Future 사용
Executor Service는 스레드 풀을 관리하며, Future는 비동기 작업의 결과를 처리할 수 있게 합니다.
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class ExecutorServiceExample { public static void main(String[] args) throws Exception { ExecutorService executor = Executors.newFixedThreadPool(2); Runnable task1 = () -> { for (int i = 0; i < 1000; i++) { System.out.println("Task 1 - " + i); } }; Runnable task2 = () -> { for (int i = 0; i < 1000; i++) { System.out.println("Task 2 - " + i); } }; Future<?> future1 = executor.submit(task1); Future<?> future2 = executor.submit(task2); future1.get(); // 작업 완료를 기다림 future2.get(); executor.shutdown(); } }
728x90반응형'자바웹프로그래밍 > JAVA' 카테고리의 다른 글
JVM의 메모리 영역에 대한 이해와 예시와 reflection의 이해 (0) 2024.07.11 jvm 클래스 로더 작동방식 (0) 2024.07.11 [JAVA] BufferedReader / BufferedWriter 왜 사용할까? (분석) (0) 2024.02.28 Reader,Writer(문자 기반 스트림) with java (0) 2024.02.27 InputStream,OutputStream 입출력 방식 분석 with java (0) 2024.02.27