[Java] 쓰레드 (Thread)

진예·2024년 1월 8일
0

JAVA

목록 보기
8/10
post-thumbnail

💡 프로세스 (Process)

실행 중인 프로그램 = 데이터 + 자원 (메모리) + 쓰레드

실행 : 프로그램메모리에 적재되어 CPU를 할당받아 기계어 명령을 수행하는 상태


💡 쓰레드 (Thread)

프로세스의 자원을 이용하여 실제로 작업을 수행하는 것


📒 멀티 쓰레딩

둘 이상의 쓰레드자원을 공유하며 작업을 수행

ex) 카톡 채팅창에서 사진을 다운로드 받으면서 채팅 가능 = 채팅창 (자원) + 다운로드 (쓰레드 1) + 채팅 (쓰레드 2)

멀티 쓰레딩 환경에서는 각 쓰레드번갈아가며 수행되는데, 이 과정에서 쓰레드 간 작업 전환 시간이 추가로 소요되며, 작업을 수행하지 않는 쓰레드에게는 대기 시간이 발생하게 된다.

서로 다른 자원을 사용하는 작업들은 멀티 쓰레드로 처리하는 것이 효율적이다.


📒 구현과 실행

📝 구현

Thread 클래스 상속 or Runnable 인터페이스 구현 ➡️ run() 구현 필수!

  • 쓰레드 생성

    • 자식 클래스 : 부모인 ThreadgetName() 호출 가능

    • 구현 클래스 : Threadstatic 메서드currentThread()를 통해 현재 실행 중인 쓰레드의 참조를 얻어와야만 getName() 호출 가능

class Thread1 extends Thread { // 클래스 상속

	@Override
	public void run() {
		for(int i=0;i<5;i++) {
			System.out.println(i + " : " + getName()); // Thread.getName();
		}
	}
}

class Thread2 implements Runnable { // 인터페이스 구현

	@Override
	public void run() {
		for(int i=0;i<5;i++) {
			System.out.println(i + " : " + Thread.currentThread().getName());
		}
	}
}
  • 인스턴스 생성

    • 자식 클래스 : 클래스 인스턴스 생성

    • 구현 클래스 : 클래스 인스턴스 생성 후, Thread 클래스의 생성자 파라미터로 제공

// 클래스 상속
Thread1 t1 = new Thread1();

// 인터페이스 구현
Runnable r = new Thread2();
Thread t2 = new Thread(r);

Thread t2 = new Thread(new Thread2());

📝 실행

start() 메서드 호출 : 각 쓰레드 당 한 번만 호출 가능!

t1.start();
t2.start();

// t1.start(); 
// IllegalThreadStateException : 이미 실행 중인 쓰레드를 호출한 경우

// 쓰레드를 다시 생성한 경우에는 가능!
t1 = new Thread1();
t1.start();

: 쓰레드들이 짧은 시간 간격으로 번갈아가면서 실행됨 (실행 순서는 OS의 스케줄러가 결정)


📝 start() & run()

  • run() : 쓰레드 클래스에 생성된 메서드 호출
  • start() : 새로운 호출 스택 생성

: main()에서 start()를 호출하면 호출 스택에 start()가 쌓이면서 가장 위에 있는 start()를 실행한다. 해당 메서드는 새로운 쓰레드를 생성하는데, 이때 해당 쓰레드에서 작업을 처리하기 위한 호출 스택이 생성된다. 즉, main()이 실행되는 쓰레드start()에 의해 새롭게 생성된 쓰레드번갈아가며 작업을 수행하는 것이다!
: start() 이후 수행할 작업이 없어 main() 메서드가 종료되면서 첫번째 쓰레드는 작업을 마쳤지만, 두번째 쓰레드에서 아직 run()을 실행중이기 때문에 프로그램이 종료되지 않는다. 즉, 모든 사용자 쓰레드의 실행이 종료되어야만 프로그램도 종료된다.

ex) throwException() : 예외를 발생시켜, 예외가 발생한 호출 스택을 출력

class Thread1 extends Thread {

	@Override
	public void run() {
		throwException();
	}
	
	public void throwException() {
		try {
			throw new Exception();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
}
  • run() : 호출 스택에 main() 포함 ➡️ main()이 실행된 쓰레드run()이 호출된 형태
public class Test{
	public static void main(String[] args) {
		Thread t1 = new Thread1();
		t1.run();
	}
}

  • start() : 호출 스택에 쓰레드 관련 메서드만 존재 ➡️ 새로운 쓰레드 및 호출 스택 생성
public class Test{
	public static void main(String[] args) {
		Thread t1 = new Thread1();
		t1.start();
	
	}
}


📒 동기화 (Synchronization)

한 쓰레드가 진행 중인 작업다른 쓰레드가 간섭하지 못하도록 막는 것

: 멀티 쓰레드 프로세스에서는 모든 쓰레드가 같은 자원을 공유해서 사용한다.

예를 들어, 쓰레드1에서 자원1을 가지고 작업을 수행하다가 쓰레드2로 제어권이 넘어간 경우, 쓰레드2에서 쓰레드1에서 사용하던 자원1의 값을 변경하면 이후 쓰레드1의 작업 수행 결과가 의도했던 결과와 다를 수 있다.

이와 같은 경우를 방지하기 위해, 공유 자원을 사용하는 코드 영역임계 영역(critical section)으로 지정하고, 공유 자원의 lock을 획득한 단 하나의 쓰레드임계 영역의 코드를 수행할 수 있게 해야 한다.

profile
백엔드 개발자👩🏻‍💻가 되고 싶다

0개의 댓글