본문 바로가기
Java

[Java] 자바 Thread(스레드) 사용법 & 예제

by Real Iron 2019. 2. 25.

▶Thread란? 

하나의 프로세스 내부에서 독립적으로 실행되는 하나의 작업 단위를 말하며, 세부적으로는 운영체제에 의해 관리되는 하나의 작업 혹은 태스크를 의미합니다. 스레드와 태스크(혹은 작업)은 바꾸어 사용해도 무관합니다.


1. JVM에 의해 하나의 프로세스가 발생하고 main( ) 안의 실행문 들이 하나의 스레드입니다.

2. main( ) 이외의 또 다른 스레드를 만들려면 Thread 클래스를 상속하거나 Runnable 인터페이스를 구현합니다.

3. 다중 스레드 작업 시에는 각 스레드 끼리 정보를 주고받을 수 있어 처리 과정의 오류를 줄일 수 있습니다.

4. 프로세스끼리는 정보를 주고받을 수 없습니다.


멀티스레딩이란?

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


장점

1. 메모리 공유로 인한 시스템 자원 소모가 줄어 듭니다.

2. 동시에 두가지 이상의 활동을 하는 것이 가능해집니다.

단점

1. 서로 자원을 소모하다가 충돌이 일어날 가능성이 존재합니다.

2. 코딩이 난해해져 버그생성확률이 높아집니다.


▶Thread의 생성주기 

thread

Runnable 상태 : 쓰레드가 실행되기위한 준비 단계

Running 상태 : 스케줄러에 의해 선택된 쓰레드가 실행되는 단계

Blocked 상태 : 쓰레드가 작업을 완수하지 못하고 잠시 작업을 멈추는 단계


스레드의 생명 주기

1. Runnable (준비상태)

스레드가 실행되기 위한 준비단계입니다. CPU를 점유하고 있지않으며 실행(Running 상태)을 하기 위해 대기하고 있는 상태입니다. 코딩 상에서 start( ) 메소드를 호출하면 run( ) 메소드에 설정된 스레드가 Runnable 상태로 진입합니다. “Ready“ 상태라고도 합니다.


2. Running (실행상태)

CPU를 점유하여 실행하고 있는 상태이며 run() 메서드는 JVM만이 호출 가능합니다. Runnable(준비상태)에 있는 여러 스레드 중 우선 순위를 가진 스레드가 결정되면 JVM이 자동으로 run( ) 메소드를 호출하여 스레드가 Running 상태로 진입합니다.


3. Dead (종료상태)

Running 상태에서 스레드가 모두 실행되고 난 후 완료 상태입니다. “Done” 상태라고도 한다.


4. Blocked (지연 상태)

CPU를 점유권을 상실한 상태입니다. 후에 특정 메서드를 실행시켜 Runnable(준비상태)로 전환합니다.

wait( ) 메소드에 의해 Blocked 상태가 된 스레드는 notify( ) 메소드가 호출되면 Runnable 상태로 간다.

sleep(시간) 메소드에 의해 Blocked 상태가 된 스레드는 지정된 시간이 지나면 Runnable 상태로 간다.


▶Thread 예제 

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

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(){
	    for(int start:temp){
		try {
			Thread.sleep(1000);
				
		} catch (InterruptedException ie) {
			ie.printStackTrace();
			// TODO: handle exception
		}
		System.out.println("스레드이름:"+currentThread().getName());
		System.out.println("temp value :"+start);
	}
    }
	
    public static void main(String[] args) {
	SingleThreadEx st = new SingleThreadEx("첫번째");
	st.start();
    }
}


2. Single Thread (Runnable 인터페이스 상속) -> 1번 방법보다 더 많이 쓰입니다.

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() {
	// TODO Auto-generated method stub
	for(int start:temp){
		try {
			Thread.sleep(1000);
				
		} catch (InterruptedException ie) {
			ie.printStackTrace();
			// TODO: handle exception
		}
			
		System.out.println("스레드이름:"+Thread.currentThread().getName());
		System.out.println("temp value :"+start);
	}
    }
	
    public static void main(String[] args) {

	SingleThreadEx2 ct = new SingleThreadEx2();
	Thread t = new Thread(ct,"첫번째");

	t.start();
    }
}

예제1


3. Mutil Thread(1)

public class Main {
    public static void main(String[] args) {
	ThreadEX threadex = new ThreadEX();
	ThreadEX threadex2 = new ThreadEX();
	Thread thread1 = new Thread(threadex,"A");
	Thread thread2 = new Thread(threadex2,"B");
		
	thread1.start();
	thread2.start();
		
	Thread.currentThread().getName();
    }
}

public class ThreadEX implements Runnable{

    int TestNum=0;
    @Override
    public /*synchronized 하나가 끝나야 실행됨*/ void run() {
	// TODO Auto-generated method stub
	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);
			
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	 }
      }
}

예제2


4. Mult Thread(2)

class ATM implements Runnable {
    private long depositeMoney = 10000;

    public void run() {
	synchronized (this) {
			
	    for (int i = 0; i < 10; i++) {
	           notify();
		try {
			wait();
			Thread.sleep(1000);
		} 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;
    }
}

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();
	son.start();
    }
}

예제3