기술 학습

JAVA 멀티스레딩(Multithreading)과 동기화(Synchronization)

EpicArts 2025. 2. 22. 19:18

1. 멀티스레딩이란?

멀티스레딩(Multithreading)은 하나의 프로세스 내에서 여러 개의 스레드를 실행하여 작업을 병렬로 수행하는 기술입니다. 이를 통해 CPU 활용도를 극대화하고 프로그램의 성능을 향상시킬 수 있습니다.

✅ 멀티스레딩의 주요 특징

  • 병렬 처리 가능: 여러 작업을 동시에 수행하여 실행 속도 향상
  • 리소스 공유: 하나의 프로세스 내에서 여러 스레드가 같은 메모리를 공유 가능
  • 스레드 간 간섭 가능성: 동기화 문제 발생 가능

2. Java에서 스레드 생성 방법

2.1 Thread 클래스를 상속하는 방법

class MyThread extends Thread {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " 실행 중");
        }
    }
}

public class ThreadExample {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();
        thread1.start();
        thread2.start();
    }
}

Thread 클래스를 상속받아 run() 메서드를 오버라이딩하면 새로운 스레드를 생성할 수 있습니다.

2.2 Runnable 인터페이스를 구현하는 방법

class MyRunnable implements Runnable {
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + " 실행 중");
        }
    }
}

public class RunnableExample {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new MyRunnable());
        Thread thread2 = new Thread(new MyRunnable());
        thread1.start();
        thread2.start();
    }
}

Runnable 인터페이스를 구현하면 보다 유연하게 스레드를 활용할 수 있습니다.


3. 스레드 동기화(Synchronization)

멀티스레딩 환경에서는 여러 스레드가 동시에 공유 자원에 접근하면 충돌이 발생할 수 있습니다. 이를 방지하기 위해 **동기화(Synchronization)**를 적용해야 합니다.

3.1 synchronized 키워드 사용

class Counter {
    private int count = 0;
    
    public synchronized void increment() {
        count++;
    }
    
    public int getCount() {
        return count;
    }
}

public class SynchronizedExample {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) counter.increment();
        });
        
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) counter.increment();
        });
        
        t1.start();
        t2.start();
        
        t1.join();
        t2.join();
        
        System.out.println("최종 카운트: " + counter.getCount());
    }
}

synchronized 키워드를 사용하면 특정 메서드가 동시에 실행되지 않도록 보장할 수 있습니다.

3.2 ReentrantLock 사용

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Counter {
    private int count = 0;
    private final Lock lock = new ReentrantLock();
    
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
    
    public int getCount() {
        return count;
    }
}

public class LockExample {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) counter.increment();
        });
        
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) counter.increment();
        });
        
        t1.start();
        t2.start();
        
        t1.join();
        t2.join();
        
        System.out.println("최종 카운트: " + counter.getCount());
    }
}

ReentrantLock을 사용하면 synchronized보다 세밀한 제어가 가능합니다.


4. 스레드 풀(Thread Pool) 활용

스레드 풀은 필요할 때마다 새로운 스레드를 생성하는 대신, 미리 생성된 스레드를 재사용하여 성능을 최적화하는 기법입니다.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        
        for (int i = 0; i < 5; i++) {
            executor.submit(() -> System.out.println(Thread.currentThread().getName() + " 실행 중"));
        }
        
        executor.shutdown();
    }
}

ExecutorService를 활용하면 스레드의 생성과 종료를 효과적으로 관리할 수 있습니다.


5. 결론

이번 글에서는 Java의 멀티스레딩 개념과 동기화 기법에 대해 살펴보았습니다. Thread, Runnable, synchronized, ReentrantLock, 그리고 ExecutorService를 활용하여 멀티스레딩 환경에서 효율적인 동시 실행을 구현할 수 있습니다.

다음 글에서는 Java의 동시성(Concurrency)과 병렬성(Parallelism)의 차이점과 활용법에 대해 알아보겠습니다!