Java에서 스레드 생성 방법

스레드는 운영 체제가 작업을 스케줄링할 수 있는 가장 작은 실행 단위입니다. 프로세스 내부에 포함되어 있으며, 하나의 프로세스는 여러 개의 스레드를 가질 수 있습니다. 각 스레드는 독립적으로 다른 작업을 수행합니다.

1. Thread 클래스 상속

Thread 클래스를 상속하고 run 메서드를 재정의한 다음 start 메서드를 호출하여 스레드를 시작할 수 있습니다.

public class CustomThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("작업 중: " + i);
        }
    }

    public static void main(String[] args) {
        CustomThread thread = new CustomThread();
        thread.start();

        for (int i = 0; i < 50; i++) {
            System.out.println("메인 작업: " + i);
        }
    }
}

2. Runnable 인터페이스 구현

Runnable 인터페이스를 구현하고 run 메서드를 재정의하면 단일 상속의 제약을 피할 수 있습니다. 이 방식은 더 일반적으로 사용됩니다.

public class Task implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("작업 진행: " + i);
        }
    }

    public static void main(String[] args) {
        Task task = new Task();
        Thread worker = new Thread(task);
        worker.start();

        for (int i = 0; i < 100; i++) {
            System.out.println("메인 스레드: " + i);
        }
    }
}

3. Callable 인터페이스 구현

Callable 인터페이스는 결과값을 반환할 수 있으며 예외 처리도 가능합니다. ExecutorService를 통해 관리할 수 있습니다.

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class AsyncTask implements Callable<Boolean> {
    private String name;

    public AsyncTask(String name) {
        this.name = name;
    }

    @Override
    public Boolean call() throws Exception {
        Thread.sleep(100);
        System.out.println(name + " 작업 완료");
        return true;
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService service = Executors.newFixedThreadPool(3);

        Future<Boolean> result1 = service.submit(new AsyncTask("A"));
        Future<Boolean> result2 = service.submit(new AsyncTask("B"));
        Future<Boolean> result3 = service.submit(new AsyncTask("C"));

        System.out.println("결과1: " + result1.get());
        System.out.println("결과2: " + result2.get());
        System.out.println("결과3: " + result3.get());

        service.shutdown();
    }
}

추가 설명

정적 프록시 패턴 예제

프록시 패턴을 이용해 실제 객체와 대리 객체 사이에서 작업을 처리할 수 있습니다.

public class ProxyExample {
    public static void main(String[] args) {
        Event event = new ProxyHandler(new RealEvent());
        event.perform();
        
        // 람다 표현식으로 스레드 생성
        new Thread(() -> System.out.println("새로운 스레드")).start();
    }
}

interface Event {
    void perform();
}

class RealEvent implements Event {
    @Override
    public void perform() {
        System.out.println("실제 이벤트 실행");
    }
}

class ProxyHandler implements Event {
    private Event target;

    public ProxyHandler(Event target) {
        this.target = target;
    }

    @Override
    public void perform() {
        before();
        target.perform();
        after();
    }

    private void before() {
        System.out.println("이전 작업 수행");
    }

    private void after() {
        System.out.println("이후 작업 수행");
    }
}

람다 표현식 사용

함수형 인터페이스를 사용하면 람다 표현식으로 간단히 코드를 작성할 수 있습니다.

public class LambdaTest {
    public static void main(String[] args) {
        Animal animal = (type1, type2) -> {
            System.out.println(type1 + " 동물 움직임");
            System.out.println(type2 + " 동물 움직임");
        };

        animal.move("고양이", "강아지");
    }
}

interface Animal {
    void move(String type1, String type2);
}

태그: java Thread concurrency

6월 9일 16:27에 게시됨