본문 바로가기
프로그래밍/JAVA

35 Thread

by 윤지(●'◡'●) 2021. 5. 4.
반응형

 


 

Thread

 

쓰레드에 대해 알기 전, 프로그램과 프로세스에 대해 간단하게 알아보자

 

프로그램  실행 안 된 상태
프로세스 실행된 프로그램.
운영체제로부터 시스템 자원을 할당받는 작업의 단위.
운영체제 대신 JVM에 스케줄링 요청을 통하여 쓰레드가 실행된다.

 

 


 

스레드(thread)란?

 

스레드(thread)란 프로세스(process) 내에서 실제로 작업을 수행하는 주체를 의미한다.

모든 프로세스에는 한 개 이상의 스레드가 존재하여 작업을 수행한다.

또한, 두 개 이상의 스레드를 가지는 프로세스를 멀티스레드 프로세스(multi-threaded process)라고 한다.

 

 

  단일쓰레드 멀티쓰레드
설명 앞의 작업이 안되면 뒤에도 안된다.
하지만 동시에 시작하지 않기 때문에 한 개에 오류가 발생해도 다른 작업은 이상이 없다.
ex) 매표소
하나의 처리 경로를 여러 개의 경로로 나누어 가질 수 있도록 한다.
특정 웹 서버는 멀티 쓰레드 응용프로그램이다.
ex) 음식점
장점 안정적이다.
설계가 상대적으로 쉽다.
효율성 증가
처리량 증가
처리비용 감소
단점 비효율적이다.
처리비용 증가.
복잡하고 설계가 어려움
자원의 공유문제(동기화)
하나의 쓰레드 문제 발생 시 다 문제 발생
교착상태

 

 

교착상태(DeadLock)

멀티 쓰레드 중 쓰레드 간에 대기 상태가 종료되지 않아서 무한정 대기하는 비정상적인 상태이다.

 

- 오라클은 DB에서 교착상태가 발생하면 60초가 걸린다.
- 교착상태를 해결하기 위해서는 하나의 쓰레드를 없애거나, 전체 쓰레드를 깨워준다.
- 교착상태가 최대한 발생되지 않게끔 제어문과 예외처리 문법으로 꼼꼼히 설계해주어야만 한다.

 


멀티쓰레드의 생성과 실행

run() 메소드 정의 후 start()로 스케줄링을 해야한다.

 

 

- Thread 클래스 상속

Thread 클래스 안에 run() 메소드와 start() 메소드가 선언되어 있다.


- Runnable 인터페이스 지정

run() 메소드는 Runnable 인터페이스 안에 추상 메소드로 선언되며,  start() 메소드는 선언되지 않는다.

 

생성해보자 !

 

Thread1 클래스

public class Thread1 extends Thread {
			/*Thread 상속*/
	private String data;

	public Thread1(String data) {
		super();
		this.data = data;
	}
	
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(data);
			 /*실행 속도가 너무 빨라 sleep을 이용해 속도를 늦춘다*/
			try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} 
		}
	}

}

 

Thread2 클래스

 

public class Thread2 implements Runnable{
		/*Runnable 인터페이스 지정*/
	private String data;

	public Thread2(String data) {
		super();
		this.data = data;
	}

	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(data);
			//보통 실시간 처리 때매 멀티 쓰레드를 구현하게 되는데,
			//원하는 쓰레드를 종료시키고 싶어도 while true안에 로직이 작성되어 있기 때문에
			//직접 break를 사용하는 방벅밖에 없다.
			//만약 제어문으로 break를 사용하지 못한다면, 일부러 InterruptedException을 발생 시킨 후
			//catch문에서 break를 사용하여 해당 쓰레드를 종료시킨다.
			try {Thread.sleep(1000);} catch (InterruptedException e) {;}
		}
	}
}

 

 

Main

 

[단일 쓰레드]

Thread1 t1 = new Thread1("★");
Thread1 t2 = new Thread1("♥");
		
t1.run();
t2.run();

 

★
★
★
★
★
★
★
★
★
★
♥
♥
♥
♥
♥
♥
♥
♥
♥
♥

별의 출력이 모두 끝난 후 하트의 출력이 시작된다(단일쓰레드)

 

 

 

[멀티 쓰레드]

Thread1 t1 = new Thread1("★");
Thread1 t2 = new Thread1("♥");

/*start(): 해당객체에 재정의된 run 메소드를 스케줄링 해준다.*/
t1.start();
t2.start();

 

 

★
♥
★
♥
★
♥
★
♥
★
♥
★
♥
★
♥
★
♥
★
♥
★
♥

별과 하트가 번갈아가며 출력된다. (멀티쓰레드)

 

 

그렇다면 Runnable 인터페이스를 지정받은 Thread2 클래스로 start()메소드를 사용하는 방법은 무엇일까?

 

public class ThreadTest{
	public static void main(String[] args) {
		Thread1 t1 = new Thread2("!");
		Thread2 t2 = new Thread2("?");
		
		Thread thread1 = new Thread(t1);
		Thread thread2 = new Thread(t2);
        /*
		Thread1은 Thread 클래스를 상속받았으므로  start()메소드가 사용가능하다
		하지만 Thread2는 Runnable 인터페이스를 지정받아 start()메소드를 바로 사용할 수 없다
		Thread 타입의 객체를 생성하고 그 객체에게 run 메소드를 가지고 있는 객체인 t1, t2를 전달한다.
		Thread() 생성자는 Runnable 타입을 받을 수 있는 이유는? 업캐스팅
		*/
		thread1.start();
		thread2.start();

 

 

Thread의 우선순위

 

쓰레드 실행이 종료된 후 "메인 쓰레드 종료"라는 문자열을 출력하고 싶을 때 아래와 같은 코드를

짰다고 생각해보자

 

Thread1 t1 = new Thread1("★");
Thread1 t2 = new Thread1("♥");

t1.start();
t2.start();	
System.out.println("메인 쓰레드 종료");

 

하지만 결과는 예상과는 다르게 "메인 쓰레드 종료"가 먼저 출력되고 쓰레드가 실행되는 것을 확인할 수 있다.

 

메인쓰레드 종료
★
♥
★
♥
★
♥
★
♥
★
♥
★
♥
★
♥
★
♥
★
♥
★
♥

 

그 이유는 우선 순위 때문인데 , 이때 다른 쓰레드의 우선 순위를 main 쓰레드보다 높게 주고 싶을 때

join() 메소드를 사용하면 된다.

join() 메소드에서 예외(InterruptedException)가 발생할 수 있으므로, 예외처리를 해주어야한다.

 

Thread1 t1 = new Thread1("★");
Thread1 t2 = new Thread1("♥");

try {
	t1.join();
	t2.join();
	} catch (InterruptedException e) {;}
		System.out.println("메인쓰레드 종료");

 

★
♥
★
♥
★
♥
★
♥
★
♥
★
♥
★
♥
★
♥
★
♥
★
♥
메인쓰레드 종료

 

 

이미지 출처 : https://eun-jeong.tistory.com/20

열심히 공부하고 있지만, 오류 사항이 존재 할 수 있습니다.

수정 사항이 존재 할 경우 알려주시면 감사하겠습니다 <(__)>

반응형

'프로그래밍 > JAVA' 카테고리의 다른 글

37 멀티쓰레드를 이용한 문제 풀이  (0) 2021.05.04
36 동기화(synchronized)  (0) 2021.05.04
34 Map 컬렉션 클래스(HashMap)  (0) 2021.04.29
33 Set 컬렉션 클래스(HashSet)  (0) 2021.04.29

댓글