Computer Language/JAVA

[JAVA] JAVA Thread(스레드) 사용법 & 예제

꽁치_로그 2022. 12. 31. 16:16

Thread란?


  • 하나의 프로세스 내부에서 독립적으로 실행되는 하나의 작업 단위
  • 운영체제에 의해 관리되는 하나의 작업(Task)
  • Thread = Task(작업)

 

  1. JVM에 의해 하나의 프로세스가 발생하고 main() 안의 실행문들이 하나의 스레드
  2. main() 이외의 또 다른 스레드를 만들려면 Thread 클래스를 상속하거나 Runnable 인터페이스 구현
  3. 멀티 스레드 작업 시, 각 스레드끼리 정보를 주고받을 수 있어 처리 과정의 오류를 줄일 수 있음
  4. 프로세스끼리는 정보 교환 불가능

멀티 스레드(Multi Thread)란?


여러 스레드를 동시에 실행시키는 응용프로그램을 작성하는 기법

장점

  1. 메모리 공유로 인한 시스템 자원 소모 줄어듬
  2. 동시 작업이 가능

단점

  1. 자원을 공유하기에 충돌 발생 가능성 존재
  2. 로직의 복잡도가 증가하여 버그 생성확률 증가

Thread 생명주기


1. Runnable (준비상태) 

  • 스레드가 실행되기 위한 준비 단계
  • CPU를 점유하고 있지 않으며 실행(Running)을 하기 위한 대기 상태
  • start() 메소드 호출 시 run() 메소드에 설정된 스레드가 Runnable 상태로 진입
  • "Ready" 상태

2. Running (실행상태)

  • CPU를 점유하여 실행하고 있는 상태
  • JVM에 의해 run() 호출
  • Runnable 상태의 여러 스레드 중 우선 순위를 가진 스레드를 JVM이 run() 호출로 해당 스레드 Running 상태로 진입

3. Dead (종료상태)

  • Running 상태의 스레드가 모두 실행되고 난 후 완료 상태
  • "Done" 상태

4. Blocked (지연상태)

  • CPU 점유권을 상실한 상태
  • 후에 특정 메소드 호출로 Runnable (준비상태)로 상태 전환
  • wait() 메소드로 Blocked 상태가 된 스레드는 notify() 메소드 호출로 인해 Runnable (준비상태)로 상태 전환
  • sleep(시간) 메소드에 의해 Blocked 상태가 된 스레드는 지정된 시간 지난 후 Runnable (준비상태)로 상태 전환

Thread 예제


1. Single Thread (Thread 클래스 상속)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.example.demo;
 
public class SingleThreadEx extends Thread{
    private int[] temp;
    public SingleThreadEx(String threadname){
        super(threadname);
        temp = new int[10];
 
        for (int start = 0; start < temp.length; start++ ){
            temp[start] = start;
        }
    }
 
    public void run(){               // Runnable -> Running
        for(int start:temp){
            try{
                Thread.sleep(1000);  // Running -> Blocked (1초마다 호출)
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("스레드 이름 : " + currentThread().getName());
            System.out.println("temp value : " + start);
 
        }
    }
 
    public static void main(String[] args){
        SingleThreadEx st = new SingleThreadEx("첫 번째"); // new
        st.start();  // new -> Runnable
    }
 
}
cs
스레드 이름 : 첫 번째
temp value : 0
스레드 이름 : 첫 번째
temp value : 1
스레드 이름 : 첫 번째
temp value : 2
....
스레드 이름 : 첫 번째
temp value : 9

2. Single Thread (Runnable 인터페이스 상속)  : 1 방법보다 많이 쓰임

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.example.demo;
 
public class SingleThreadEx2 implements Runnable{
    private int[] temp;
    public SingleThreadEx2(){
        temp = new int[10];
 
        for (int start = 0; start < temp.length; start++ ){
            temp[start] = start;
        }
    }
 
    @Override
    public void run(){
        for(int start:temp){
            try{
                Thread.sleep(1000);  // Running -> Blocked (1초마다 호출)
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("스레드 이름 : " + Thread.currentThread().getName());
            System.out.println("temp value : " + start);
 
        }
    }
 
    public static void main(String[] args){
        SingleThreadEx2 st = new SingleThreadEx2();
        Thread t = new Thread(st, "첫번째");
 
        t.start();
    }
 
}
cs
스레드 이름 : 첫 번째
temp value : 0
스레드 이름 : 첫 번째
temp value : 1
스레드 이름 : 첫 번째
temp value : 2
....
스레드 이름 : 첫 번째
temp value : 9

3. Multi Thread 

Main.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.example.demo;
 
public class Main {
    public static void main(String[] args) {
        ThreadEx threadEx1 = new ThreadEx();
        ThreadEx threadEx2 = new ThreadEx();
        Thread thread1 = new Thread(threadEx1, "A");
        Thread thread2 = new Thread(threadEx2, "B");
 
        // 동기로 thread1 끝나고 thread2 실행
        thread1.start();
        thread2.start();
        
    }
 
}
cs

Thread.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.example.demo;
 
import org.aspectj.weaver.ast.Test;
 
public class ThreadEx implements Runnable{
    int TestNum = 0;
 
    @Override
    public void run() {  // 스레드가 수행할 로직
 
        for(int i=0; i<10; i++){
            if(Thread.currentThread().getName().equals("A")){
                System.out.println("===================");
                TestNum++;
            }
            System.out.println("ThreadName = " + Thread.currentThread().getName() + " TestNum = " + TestNum);
 
        }
    }
}
 
cs
===================
ThreadName = A TestNum = 1
===================
ThreadName = A TestNum = 2
===================
ThreadName = A TestNum = 3
===================
ThreadName = A TestNum = 4
===================
ThreadName = A TestNum = 5
===================
ThreadName = A TestNum = 6
===================
ThreadName = A TestNum = 7
===================
ThreadName = A TestNum = 8
===================
ThreadName = A TestNum = 9
===================
ThreadName = A TestNum = 10
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0
ThreadName = B TestNum = 0

4. Multi Thread 예제 : 동기화

ATM.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package com.example.demo;
 
import lombok.Synchronized;
 
public class ATM implements Runnable{
    private long depositeMoney = 10000;
 
    @Override
    public void run() {
 
        synchronized (this) {
            for (int i = 0; i < 10; i++) {
                notify();           // Blocked -> Runnable
                try {
                    wait();         // Running -> Blocked
                    Thread.sleep(1000); // 1초마다 호출
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
 
                if (getDepositeMoney() <= 0)
                    break;
 
                withDraw(1000);
            }
        }
 
    }
 
    public void withDraw(long howMuch){
        if(getDepositeMoney() > 0){
            depositeMoney -= howMuch;
            System.out.print(Thread.currentThread().getName() + " , ");
            System.out.printf("잔액 : %,d 원 %n", getDepositeMoney() );
        } else{
            System.out.print(Thread.currentThread().getName() + " , ");
            System.out.println("잔액이 부족합니다.");
        }
    }
 
    public long getDepositeMoney(){
        return depositeMoney;
    }
}
 
 
cs

Synchronized.java

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.example.demo;
 
public class SynchronizedEx {
    public static void main(String[] args) {
        ATM atm = new ATM();
        Thread mother = new Thread(atm, "mother");
        Thread son = new Thread(atm, "son");
        mother.start(); // new -> Runnable
        son.start();
    }
}
 
 
cs
mother , 잔액 : 9,000 원
son , 잔액 : 8,000 원
mother , 잔액 : 7,000 원
son , 잔액 : 6,000 원
mother , 잔액 : 5,000 원
son , 잔액 : 4,000 원
mother , 잔액 : 3,000 원
son , 잔액 : 2,000 원
mother , 잔액 : 1,000 원
son , 잔액 : 0 원
반응형

'Computer Language > JAVA' 카테고리의 다른 글

[JAVA] Map 전체 출력(entrySet, keySet, Iterator)  (0) 2022.09.27