ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • java에서의 동시성 이슈 제어방법
    자바웹프로그래밍/JAVA 2024. 7. 10. 16:55
    728x90
    반응형

     

     

     

    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
    반응형
Designed by Tistory.