JAVA

자바 기본 다지기 최종

도원좀비 2025. 2. 27. 20:27

쓰레드(Thread)란?

  • 쓰레드는 프로그램 내에서 독립적으로 실행되는 하나의 작업 단위
  • 싱글 쓰레드 는 한 번에 하나의 작업만 처리하지만 멀티쓰레드는 여러 작업을 동시에 처리 가능
  • 멀티 쓰레드를 활용하면 여러 작업을 병렬로 수행할 수 있어 처리 성능을 향상시킬 수 있다.

싱글 쓰레드(Single Thread) 

  • 싱글 쓰레드는 한 명의 일꾼이 작업을 처리하는 것과 같습니다.
  • 일꾼이 한 명이기 때문에 여러 개의 작업이 있다면 순차적으로 처리해야 합니다.
  • main() 메서드는 프로그램 시작과 동시에 생성되는 하나의 쓰레드입니다.
public class Main {

    public static void main(String[] args) {
        System.out.println("::: main 쓰레드 시작 :::");
        String threadName = Thread.currentThread().getName();
        
        // 하나의 작업 단위: 숫자를 0 부터 9 까지 출력
        for (int i = 0; i < 10; i++) {
            System.out.println("현재 쓰레드: " + threadName + " - " + i);
            try {
                Thread.sleep(500); // 0.5 초 대기
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 추가작업
        for (int i = 0; i < 10; i++) {
            System.out.println("현재 쓰레드: " + threadName + " - " + i);
            try {
                Thread.sleep(500); // 0.5 초 대기
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("::: 작업 끝 :::");
    }
}

 

 

멀티 쓰레드(Multi-Thread)

  • 멀티쓰레드는 작업을 처리할 수 있는 여러 명의 일꾼을 의미
  • 멀티 쓰레드를 활용해서 여러 작업(0 ~9 출력)을 병렬(동시)로 처리 가능
  • Thread 클래스를 상속받아 쓰레드를 구현 가능
  • Thread.run() 메서드를 오버라이드 해서 쓰레드가 수행할 작업을 정의
  • start() 메서드를 호출하면 새로운 쓰레드가 생성되고 run() 의 작업 내용이 실행
  • 총 세 개의 쓰레드(main, thread0, thread1) 병렬로 실행
  • main 쓰레드는 thread0, thread1 을 생성하고 실행
// Thread 클래스 상속으로 쓰레드 구현
public class MyThread extends Thread {

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        System.out.println("::: " + threadName + "쓰레드 시작 :::");
        for (int i = 0; i < 10; i++) {
            System.out.println("현재 쓰레드: " + threadName + " - " + i);
            try {
                Thread.sleep(500); // 딜레이 0.5 초
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("::: " + threadName + "쓰레드 종료 :::");
    }
}


public class Main {

    public static void main(String[] args) {
        System.out.println("::: main 쓰레드 시작");

        MyThread thread0 = new MyThread();
        MyThread thread1 = new MyThread();

        // 1. thread0 실행
        System.out.println("::: main 이 thread0 을 실행");
        thread0.start();

        // 2. thread1 실행
        System.out.println("::: main 이 thread1 을 실행");
        thread1.start();

        System.out.println("::: main 쓰레드 종료");
    }
}

 

 

join() - 특정 쓰레드가 끝날 때까지 기다리기

  • join() 은 main() 쓰레드가 다른 쓰레드가 종료될 때까지 기다리게 하는 메서드
  • join() 을 호출한 쓰레드가 끝날 때까지 main() 쓰레드가 대기
  • main() 쓰레드가 너무 빨리 끝나지 않고 모든 작업이 완료된 후 종료되도록 할 때 유용
public class Main {

    public static void main(String[] args) {
        System.out.println("::: main 쓰레드 시작");
        MyThread thread0 = new MyThread();
        MyThread thread1 = new MyThread();

        // 시작시간 기록
        long startTime = System.currentTimeMillis();

        // 1. thread0 시작
        System.out.println("thread0 시작");
        thread0.start();

        // 2. thread1 시작
        System.out.println("thread1 시작");
        thread1.start();

        // ⌛️ main 쓰레드 대기 시키기
        try {
            thread0.join();
            thread1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long endTime = System.currentTimeMillis();
        long totalTime = endTime - startTime;
        System.out.println("총 작업 시간: " + totalTime + "ms");
        System.out.println("::: main 쓰레드 종료");
    }
}

 

Runnable 인터페이스 활용

  • 멀티 쓰레드의 쓰레드와 동일하지만 2가지의 장점을 소유
  1. 유지보수성과 재사용성 향상
  2. 확장 가능성
public class MyNewClass { // 새로운 클래스 

    public void printMessage() {
        System.out.println("MyClass 기능 실행");
    }
}

////////////////// 불가능한 클래스 //////////////////////////
public class MyThread extends Thread, MyNewClass{ // 다중 상속 불가
		...
}
////////////////////////////////////////////////////////////

public class MyRunnable extends MyNewClass implements Runnable { // 다중 상속

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        for (int i = 0; i < 10; i++) {
            System.out.println("현재 쓰레드: " + threadName + " - " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


public class Main {

    public static void main(String[] args) {

        MyRunnable task = new MyRunnable();

        // 기존 클래스를 유지하면서 확장해서 활용
        task.printMessage(); 

        Thread thread0 = new Thread(task);
        Thread thread1 = new Thread(task);

        thread0.start();
        thread1.start();
    }
}

 

실습과제

  • 1 부터 1000 까지의 숫자 합계를 구합니다.
  • 연산 사이에 10ms 딜레이를 추가하여 0.01초마다 계산 Thread.sleep(10);
  • 싱글 쓰레드는 하나의 루프로 계산합니다.
  • 멀티 쓰레드는 4개의 쓰레드가 각각 숫자를 나누어 계산합니다.
    • 1 ~ 250
    • 251 ~ 500
    • 501 ~ 750
    • 751 ~ 1000
  • 두 방법의 실행 시간을 비교하여 멀티 쓰레드가 얼마나 더 빠른지 확인해 보세요.

(구현 코드)

public class SingleTask {
    public static void main(String[] args) {
        System.out.println("싱글 쓰레드 시작");
        String threadName = Thread.currentThread().getName();

        int sum = 0;

        long startTime = System.currentTimeMillis();

        for (int i = 0; i < 1000; i++) {
            sum += i;
            System.out.println("현재 쓰레드 : " + threadName + " - " + i);
            System.out.println("현재 까지 합 : " + sum);
            try {
                Thread.sleep(10);
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        long endTime = System.currentTimeMillis();
        long totalTime = endTime - startTime;

        System.out.println("합계 결과 : " + sum);
        System.out.println("작업 시간 : " + totalTime + "ms");
        System.out.println("싱글 쓰레드 종료!");
    }
}
package practice;

public class MultiTask implements Runnable {

    private int start;
    private int end;

    public MultiTask(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();

        int sum = 0;

        for (int i = start; i < end; i++) {
            sum += i;
            System.out.println("현재 쓰레드 : " + threadName + " - " + i);
            System.out.println("현재 까지 합 : " + sum);
            try {
                Thread.sleep(10);
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("쓰레드 " + threadName + "의 합계 (" + start + " ~ " + end + "): " + sum);

    }
}
package practice;

public class Main {
    public static void main(String[] args) {

        long startTime = System.currentTimeMillis();

        Thread thread0 = new Thread(new MultiTask(1,250));
        Thread thread1 = new Thread(new MultiTask(251, 500));
        Thread thread2 = new Thread(new MultiTask(501, 750));
        Thread thread3 = new Thread(new MultiTask(751, 1000));

        thread0.start();
        thread1.start();
        thread2.start();
        thread3.start();

        try {
            thread0.join();
            thread1.join();
            thread2.join();
            thread3.join();
        }catch (InterruptedException e) {
            e.printStackTrace();
        }

        long endTime = System.currentTimeMillis();
        long totalTime = endTime - startTime;
        System.out.println("걸린시간 : " + totalTime + "ms");

    }
}

'JAVA' 카테고리의 다른 글

쓰레드(Thread)  (0) 2025.03.11
Java Stream API 주요 메서드 정리  (2) 2025.02.28
자바 기초 문법 다지기 4  (1) 2025.02.26
자바 기초 문법 다지기 3  (1) 2025.02.26
자바 기초 문법 다지기3  (0) 2025.02.26