상세 컨텐츠

본문 제목

[JAVA] Multi-Thread 사용법

Spring/개념

by Chan.94 2022. 3. 2. 12:18

본문

반응형

Main Thread

Java Application은 Main Thread가 main() 메소드를 실행하면서 시작된다.

Main Thread 흐름 안에서 필요에 따라 쓰레드를 만들어 병렬로 코드를 실행할 수 있다.

싱글 스레드 같은 경우 메인 스레드가 종료되면 프로세스도 종료되지만, 멀티 스레드는 메인 스레드가 종료되더라도 실행 중인 스레드가 하나라도 있다면 프로세스는 종료되지 않는다.


Thread 생성방법

Thread 클래스로부터 직접 생성

- Thread객체를 생성할 때 Runnable 인터페이스를 상속받아 구현한 객체(run 메소드 override 한)를 매개변수로 받는다.

- Thread객체 생성후 start()메소드로 Thead실행

public class MainThreadClass {
	public static void main(String[] args) {
		Thread subThread1 = new Thread(new TaskRunnable());
		Thread subThread2 = new Thread(new TaskRunnable());
		Thread subThread3 = new Thread(new TaskRunnable());
		
		subThread1.start();
		subThread2.start();
		subThread3.start();
	}
}
public class TaskRunnable implements Runnable{
	@Override
	public void run() {
		int nSum = 0;
		for (int nIdx = 0; nIdx < 5; nIdx++) {
			nSum += nIdx;
			System.out.println(Thread.currentThread().getName() + " : " + nSum);
		}
		System.out.println( Thread.currentThread().getName() + " 최종 합 : " + nSum);
	}
}
Thread-0 : 0
Thread-2 : 0
Thread-2 : 1
Thread-2 : 3
Thread-1 : 0
Thread-2 : 6
Thread-2 : 10
Thread-0 : 1
Thread-1 : 1
Thread-2 최종 합 : 10
Thread-0 : 3
Thread-1 : 3
Thread-0 : 6
Thread-1 : 6
Thread-0 : 10
Thread-1 : 10
Thread-0 최종 합 : 10
Thread-1 최종 합 : 10

 

 

Thread 클래스를 상속받아 생성

- Thread 클래스를 상속받는다.

- run() 메소드를 override하여 구현한다.

public class MainThreadClass {
	public static void main(String[] args) {
		Thread subThread1 = new TaskThread();
		Thread subThread2 = new TaskThread();
		Thread subThread3 = new TaskThread();
		
		subThread1.start();
		subThread2.start();
		subThread3.start();
	}
}
public class TaskThread extends Thread {
	@Override
	public void run() {
		int nSum = 0;
		for (int nIdx = 0; nIdx < 5; nIdx++) {
			nSum += nIdx;
			System.out.println(Thread.currentThread().getName() + " : " + nSum);
		}
		System.out.println( Thread.currentThread().getName() + " 최종 합 : " + nSum);
	}
}

Daemon Thread

- Main Thread의 보조적인 역할을 수행하는 Thread이다.

- Main Thread가 종료되면 함께 종료된다.

- setDeamon 메소드를 통해 실행시킨다.

public class MainThreadClass {
	public static void main(String[] args) throws Exception {
		Thread subThread1 = new TaskThread();
		Thread subThread2 = new TaskThread();
		Thread subThread3 = new TaskThread();
		Thread daemonThread = new DaemonThread();
		
		daemonThread.setDaemon(true);
		daemonThread.start();
		subThread1.start();
		subThread2.start();
		subThread3.start();
		
		//while문이 없다면 Main Thread가 종료되기 때문에 DaemonThread도 함께 종료된다.
		while(true) {
			Thread.sleep(100);
		}
	}
}
public class DaemonThread extends Thread{
	@Override
	public void run() {
		while(true) {
			System.out.println("DaemonThread running");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
DaemonThread running
Thread-1 : 0
Thread-2 : 0
Thread-2 : 1
Thread-2 : 3
Thread-1 : 1
Thread-1 : 3
Thread-1 : 6
Thread-1 : 10
Thread-2 : 6
Thread-1 최종 합 : 10
Thread-0 : 0
Thread-2 : 10
Thread-0 : 1
Thread-2 최종 합 : 10
Thread-0 : 3
Thread-0 : 6
Thread-0 : 10
Thread-0 최종 합 : 10
DaemonThread running
DaemonThread running
DaemonThread running
DaemonThread running
DaemonThread running
DaemonThread running
DaemonThread running
DaemonThread running

동기화 메소드 or 동기화 블록

Multi-Thread 환경에서는 각각의 Thread들이 객체를 공유하며 작업하는 경우가 발생한다.

A Thread와 B Thread가 공유하는 객체가 서로의 작업에 영향을 주어서는 안된다.

동기화 메소드 or 동기화 블록을 이용하여 방지한다.

 

 

- 동기화를 너무 남발하게 되면 오히려 성능저하가 발생 할 수 있다.

동기화 전

public class MainThreadClass {
	public static void main(String[] args) throws Exception {
		ShareClass shareClass = new ShareClass();
		
		for(int nCnt = 0 ; nCnt < 10 ; nCnt++) {
			ShareThread shareThread = new ShareThread();
			shareThread.setShareClass(shareClass);
			shareThread.start();
		}
	}
}
public class ShareThread extends Thread{
	
	private ShareClass shareClass;

	public ShareClass getShareClass() {
		return shareClass;
	}

	public void setShareClass(ShareClass shareClass) {
		this.shareClass = shareClass;
	}

	@Override
	public void run() {
		shareClass.sum();
	}

}
public class ShareClass {
	int value;
	
	public void sum() {
		System.out.println("결과 : " + this.value);
		this.value++;
	}
}
결과 : 0
결과 : 1
결과 : 0
결과 : 0
결과 : 0
결과 : 5
결과 : 5
결과 : 7
결과 : 8
결과 : 9

10개의 Thread가 1개의 ShareClass를 공유하고있다.

따라서 실행 결과는 매번 다르게 출력 될 것이다.


동기화 후 (동기화 메소드)

public class MainThreadClass {
	public static void main(String[] args) throws Exception {
		ShareClass shareClass = new ShareClass();
		
		for(int nCnt = 0 ; nCnt < 10 ; nCnt++) {
			ShareThread shareThread = new ShareThread();
			shareThread.setShareClass(shareClass);
			shareThread.start();
		}
	}
}
public class ShareThread extends Thread{
	
	private ShareClass shareClass;

	public ShareClass getShareClass() {
		return shareClass;
	}

	public void setShareClass(ShareClass shareClass) {
		this.shareClass = shareClass;
	}

	@Override
	public void run() {
		shareClass.sum();
	}

}
public class ShareClass {
	int value;
	
	public synchronized void sum() {
		System.out.println("결과 : " + this.value);
		this.value++;
	}
}

동기화 후 (동기화 블록)

public class MainThreadClass {
	public static void main(String[] args) throws Exception {
		ShareClass shareClass = new ShareClass();
		
		for(int nCnt = 0 ; nCnt < 10 ; nCnt++) {
			ShareThread shareThread = new ShareThread();
			shareThread.setShareClass(shareClass);
			shareThread.start();
		}
	}
}
public class ShareThread extends Thread{
	
	private ShareClass shareClass;

	public ShareClass getShareClass() {
		return shareClass;
	}

	public void setShareClass(ShareClass shareClass) {
		this.shareClass = shareClass;
	}

	@Override
	public void run() {
		synchronized (shareClass) {
			shareClass.sum();
		}
	}

}
public class ShareClass {
	int value;
	
	public void sum() {
		System.out.println("결과 : " + this.value);
		this.value++;
	}
}
결과 : 0
결과 : 1
결과 : 2
결과 : 3
결과 : 4
결과 : 5
결과 : 6
결과 : 7
결과 : 8
결과 : 9
반응형

관련글 더보기

댓글 영역

>