개발자 미니민의 개발스터디

[JAVA] 자바 - 스레드 (Thread) 개념

by mini_min
[JAVA]
자바 - 스레드 (Thread) 개념 

✔️ 스레드 (Thread)

프로세스와 스레드의 관계는 포함관계이다.

프로세스는 운영체제로 부터 자원을 할당받은 작업의 단위로 실행 중인 하나의 프로그램을 의미함.

✨ 프로세스 : 리소스 + 스레드 

✨ Code, Data, Heap, Stack 영역으로 이뤄지며 동시에 2개 이상의 프로그램을 동시 실행시키는 것을 멀티 태스킹이라고 한다.

 

💖 스레드는 프로스세 안에서 실행되는 흐름의 단위다. 

프로세스가 할당 받은 자원을 이용하는 실행 단위 흐름이고, 모든 프로세스는 적어도 하나 이상의 스레드를 가진다.

프로세스는 자신만의 메모리/자원을 할당 받지만, 스레드는 다른 스레드와 메모리, 자원을 공유한다.

✨ Code, Data, Heap 영역은 공유하고 별도의 Stack 영역만 가진다.

✨ 둘 이상의 스레드를 가진 프로세스를 멀티 스레드 프로세스라고 한다.

 

 

✔️ 멀티 스레드 (Multi Thread)

장점 : 시스템 자원 소모가 줄어든다. 

CPU 사용률을 향상시킨다.

프로그램 응답 시간이 단축된다.

 

단점 : 자원 공유를 위해 전역변수를 이용하므로 동기화 문제 발생

잘못된 변수 사용하거나 시간차로 프로그램에 오류 발생할 수 있다.

디버깅이 어렵다.. 🐛

 

 

✔️ 자바 메인 스레드 (Main Thread)

자바는 프로그램 시작시 기본적으로 main() 메소드를 진입 점으로 하는 메인 스레드가 생성된다.

추가로 사용자가 정의한 스레드를 생성하여 멀티 스레드를 구현할 수 있다.

💡 멀티 스레드 환경에서는 모든 스레드가 종료되어야 프로세스가 종료된다.
= 모두 종료되지 않으면 무한의 굴레가....

 

 

✔️ 스레드 구현 클래스 / 인터페이스

💖 Thread 클래스

: 스레드 생성 및 시작, 관리를 위한 클래스로 하위 클래스에서 run() 메소드를 재정의하여 스레드를 구현한다.

 

💖 Runnable 인터페이스

: 스레드에서 실행할 코드를 가지는 run() 메소드가 선언되어 있다. 

✨ 자바는 단일 상속만 구현 가능하므로 스레드를 구현할 클래스가 다른 클래스를 상속 받은 경우 Runnable 인터페이스를 구현한다. 

💡 Runnable 인터페이스를 implements 한 클래스는 run() 메소드 재정의하여 스레드 구현

 

 

✔️ 스레드 시작

: 스레드를 실행하기 위해 Thread() 클래스의 start() 메소드를 호출하면 스레드를 시작한다.

 

Thread 클래스를 상속받는 하위 클래스를 만든 경우

: 해당 하위 클래스의 객체를 생성 후 Thread() 클래스의 start() 메소드를 호출한다. 

Runnable 인터페이스를 구현하여 클래스를 만든 경우

: Thread() 생성자에 Runnable 인터페이스 구현 클래스 객체를 인수로 넘겨 Thread 클래스 객체 생성하여 Thread 클래스의 start()  메소드 호출한다. 

 

 

✔️ 스레드 구현 방법 - 1

1) Thread 클래스를 상속 받아 run() 메소드를 override 한다.

2) Thread 클래스를 상속받은 클래스의 객체를 생성하여 start() 메소드를 호출한다.

class MyThread1 extends Thread {
	
	@Override
	public void run() {
		int n = 0;
		
		try {
			while(n<20) {
				n++;
				System.out.println(getName() + "-> " + n);
				
				sleep(500);  // 지정시간 (ms) 동안 스레드 실행이 일시 중지
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
	}
    
    
    public static void main(String[] args) {
		MyThread1 t = new MyThread1();
		
		t.start(); // 스레드 시작 
		
		
		//메인이 먼저 5개 정도 찍히면 아래 스레드가 1번 정도 찍히는 정도임.
		// 메인이 일이 끝나면 나머지 아래 스레드가 찍힌다아아
		System.out.println("main 스레드..");
		try {
			for(int i=1; i<=10; i++) {
				System.out.println("main -> " + i);
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println("main 스래드 종료....");
		// 메인은 프로그램 시작점으로 종료점이 아니다.
		// 메인이 종료되어도 프로그램은 종료되지 않을 수 있다.
		// 프로그램 종료 시점은 모든 독립 스레드가 종료되는 시점이다.
		
	}
💡 sleep : ms 단위로 일시정지한다.

 

 

✔️ 스레드 구현 방법 - 2

1) Runnable 인터페이스를 구현하는 클래스를 만들어 run() 메소드를 재정의한다.

2) Runnable 구현 클래스의 객체를 생성한다.

3) Thread 클래스의 객체를 생성하며, Thread 클래스의 객체를 생성할 때 생성자에 2)번의 객체를 인자로 전달한다.

4) Thread 클래스의 객체의 start() 메소드를 호출한다. 

class MyThread2 implements Runnable {

	@Override
	public void run() {
		int n = 0;
		
		try {
			while(n < 20) { 
				n++;
				System.out.println(Thread.currentThread().getName() + "-> " + n);
				
				Thread.sleep(500);  // 지정시간 (ms) 동안 스레드 실행이 일시 중지
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
	}
public static void main(String[] args) {
		MyThread2 obj = new MyThread2();
		Thread t = new Thread(obj);
		
		t.start();
		
		
		System.out.println("main 스레드..");
		try {
			for(int i=1; i<=10; i++) {
				System.out.println("main -> " + i);
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println("main 스래드 종료....");
		
	}

}

 

 

✔️ 스레드 구현 방법 - 3

1) 익명 클래스 이용

public static void main(String[] args) {
		// 스레드 구현방법 3 : 익명 클래스
		Thread t = new Thread(new Runnable() {
			
			@Override
			public void run() {
				int n = 0;
				
				try {
					while(n < 20) { 
						n++;
						System.out.println(Thread.currentThread().getName() + "-> " + n);
						
						Thread.sleep(500);  // 지정시간 (ms) 동안 스레드 실행이 일시 중지
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				} catch (Exception e) {
					e.printStackTrace();
				}
				
			}
		});
		
		t.start();
		
		
		System.out.println("main 스레드..");
		try {
			for(int i=1; i<=10; i++) {
				System.out.println("main -> " + i);
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println("main 스래드 종료....");
		

	}

 

 

✔️ 스레드 구현 방법 - 4

1) 람다식

public static void main(String[] args) {
		// 스레드 구현 방법 4 - 람다
		Thread t = new Thread( () -> {
			int n = 0;
			
			try {
				while(n < 20) { 
					n++;
					System.out.println(Thread.currentThread().getName() + "-> " + n);
					
					Thread.sleep(500);  // 지정시간 (ms) 동안 스레드 실행이 일시 중지
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		});
		
		t.start();
		
		System.out.println("main 스레드..");
		try {
			for(int i=1; i<=10; i++) {
				System.out.println("main -> " + i);
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println("main 스래드 종료....");

	}

 

 

🔒 람다 + 스레드로 현재 시간 구하기

public static void main(String[] args) {
		Thread t = new Thread(() -> {
			String s;
			
			while(true) {
				Calendar cal = Calendar.getInstance();
				
				s = String.format("%tF %tT", cal, cal);
				System.out.println(s);
				
				try {
					Thread.sleep(1000);
				} catch (Exception e) {
				}
				
			}
		});
		
		t.start();
		
		
		System.out.println("main end...");

	}

 

 

 

 

 

 

 

블로그의 정보

개발자 미니민의 개발로그

mini_min

활동하기