본문 바로가기

STUDY/Java

[JAVA] Thread, 스레드

 
 

01. 프로그램

1. 보조기억장치 (하드디스크): 프로그램과 데이터, 영구 저장

 

2. 주기억장치

(1) 단일 프로그램: 프로그램이 1개, 속도가 느림

(2) 다중프로그램: 메모리에 여러 개의 프로그램이 존재

 

3. 중앙처리장치

(1) 제어장치: 흐름 제어, 신호등 역할

(2) 연산장치: 값을 구함

 

4. 프로그램 (Program): 보조기억장치 또는 주기억장치 <저장장치>에 기록 (실행 x)

 

5. 프로세스 (Process): 주기억장치의 프로그램이 실행되기 위해 CPU로 들어가 실행되는 프로그램

 

6. 스레드 (Thread): 프로세스를 세분화 시킨 단위, 시분할 사용(TSS, Time Sharing System)

* 자바에서 스레드가 기본 처리의 단위, 입력과 출력은 프로그램 단위

* 스레드를 이용해 병렬 처리가 가능

- 병렬 처리(Parallel Processing): 동시에 처리

- 동시에 처리하려면 CPU가 여러개 필요 -> 하지만 실제로 CPU가 여러개인 경우는 거의 없음

- CPU 하나로 병렬처리 하려면? 시분할 사용

 

 

 

02. 동기화 메소드 및 동기화 블록

1. 임계영역(Critical Section): CPU에서 실행할 때 하나의 스레드만 실행할 수 있는 코드 영역

즉, 하나의 스레드가 실행 중이면 다른 스레드는 들어올 수 없도록 영역을 구분

 

2. 동기화(Synchronized): 임계 영역에 스레드가 이미 있음을 알려줌 > 다른 스레드가 들어올 수 없도록

 

 

03. 스레드를 만드는 방법

* run() 메소드를 오버라이딩(재정의) 필수 + 재정의된 run() 메소드를 실행하려면 start() 메소드를 호출

(1) Thread 클래스를 상속

- java.lang 패키지 > Thread 클래스 > run() 메소드

package com.thread;

public class Korea extends Thread{

	@Override
	public void run() {
		for(int i=0; i<10; i++) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("홍길동");
		}
	}	
}
 

① 3행: Thread 상속

② 9행: Thread.sleep(millisecond): 1초마다 쉬기

③ 6행: 스레드에 있는 모든 메소드는 public

④ 6행: run() 메소드를 오버라이딩(재정의)

package com.thread;
public class KoreaTest {
	public static void main(String[] args) {
		Korea kor = new Korea();
		kor.start();
	}
}
 

[결과화면]


(2) Runnable 인터페이스를 상속

- java.lang 패키지 > Runnable 인터페이스 > run() 메소드(만 존재)

package com.thread;

public class KoreaInterface implements Runnable{
	
	@Override
	public void run() {
		for(int i=0; i<10; i++)
		{
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("홍길동2");
		}
	}
}
 

① 3행: Runnable 인터페이스 상속

package com.thread;
public class KoreaTest {
	public static void main(String[] args) {
		KoreaInterface korin = new KoreaInterface();
		Thread thread = new Thread(korin);
		thread.start();
	}
}
 

② 5행: 실행시키기 위해 Thread 객체를 하나 더 생성 후 start() 메소드 사용

 

[결과화면]


ex) 익명클래스를 이용하면 상속을 받지 않고 Runnable 사용 가능

package com.thread;

public class AnonyTest {
	public static void main(String[] args) {
		Runnable rr = new Runnable() {

			@Override
			public void run() {
				for(int i=0; i<10; i++) {
					System.out.println("홍길동3");
				}
			}			
		};
		Thread tt = new Thread(rr);
		tt.start();
	}	
}
 

① 8행: public void run() {}; // 익명 클래스

② 14행: Runnable을 사용했기 때문에 Thread 객체 생성

 

[결과화면]


ex) 익명 객체 이용 (익명 클래스, 익명 객체 모두 1회성)

package com.thread;

public class AnonyTest2 {
	public static void main(String[] args) {
		Thread thread = new Thread(()-> {
			for(int i=0; i<10; i++) {
				System.out.println("홍길동4");
			}
		}); // 익명객체 이용
		thread.start();
	}
}
 

① 5행: Thread thread = new Thread((0 -> {};) // 익명 객체 생성

 

[결과화면]

 

위에 4가지 방법이 스레드를 사용한 것인데 원래 쓰던 방식과 별 차이가 없어 보임 -> 아래 예제로 확인


 

04. 구구단 예제

1. 구구단 (Thread 사용 전)

package com.thread;

public class Multiplication extends Thread {
int input;

public Multiplication(int input) {
	super();
	this.input = input;
}
void print(){
	for(int i=1; i<=9; i++){
		System.out.println(this.input + " * " + i + " * " + (this.input*i));
	}
}
 
package com.thread;

import java.util.Scanner;

public class InputTest {
	public static void main(String[] args) {
		System.out.print("구구단 몇단? ");
		Scanner sc = new Scanner(System.in);
		int a = sc.nextInt();
		Multiplication result = new Multiplication(a);
		result.print();
	}
}
 

[결과화면]

 

2. 구구단 (Thread 사용, Thread 상속)

package com.thread;

public class Multiplication extends Thread {
int input;

public Multiplication(int input) {
	super();
	this.input = input;
}

public void run() {
	for(int i=1; i<=9; i++) {
		System.out.println(this.input + " * " + i + " = " + (this.input*i));
	}
}
}
 

① 3행: Thread 상속

② 11행: run() 메소드 오버라이딩 (재정의)

package com.thread;
import java.util.Scanner;

public class InputTest {
	public static void main(String[] args) {
		Multiplication result2 = new Multiplication(2);
		Multiplication result3 = new Multiplication(3);
		
		result2.start();
		result3.start();
	}
}
 

[결과화면]

* 프로그램 작성 순서는 2단과 3단이지만 순서대로 뜨지 않고 번갈아 가면서 뜨는 것이 확인 가능 -> 시분할 방법


 

3. 스레드 우선순위 설정 setPriority(Thread.MAX_PRIORITY)

package com.thread;
import java.util.Scanner;

public class InputTest {
	public static void main(String[] args) {
		Multiplication result2 = new Multiplication(2);
		Multiplication result3 = new Multiplication(3);
		Multiplication result4 = new Multiplication(4);
		
		result4.setPriority(Thread.MAX_PRIORITY);

		result2.start();
		result3.start();
		result4.start();
	}
}
 

① 10행: Thread.MAX_PRIORITY = 10; // 값이 높을수록 우선순위가 높아짐

 

[결과화면]

* 하지만 우선순위를 가장 높게 줘도 무조건 맨 처음에 뜨는 것이 아니라 확률이 높아질 뿐


 

4. 구구단 (Thread 사용, Runnable 상속)

package com.thread;

public class MultipleInterface implements Runnable{

	int input;
	
	public MultipleInterface(int input) {
		this.input = input;
	}

	@Override
	public void run() {
		for(int i=1; i<=9; i++) {
			System.out.println(this.input + " * " + i + " = " + (this.input*i));
		}
	}

	public static void main(String[] args) {
		MultipleInterface m2 = new MultipleInterface(2);
		Thread t2 = new Thread(m2);
		t2.start();
		
		Thread t3 = new Thread(new MultipleInterface(3));
		t3.start();	
	}
}
 

[결과화면]

* Thread 상속과 방식의 차이 -> 둘 다 시분할

 


 

05. 스레드 상태 제어

(1) UpDown.java

package com.thread;

public class UpDown {
	int data;
	
	public UpDown(int data) {
		super();
		this.data = data;
	}

	public synchronized void up() {
		data++;
		System.out.println("증가 " + data);
	}
	
	public synchronized void down() {
		data--;
		System.out.println("감소 " + data);
	}
}
 

(2) UpThread.java

package com.thread;

public class UpThread extends Thread{
	UpDown data; // UpDown클래스에서 공통으로 사용할 data를 호출해 사용

	public UpThread(UpDown data) {
		super();
		this.data = data;
	}
	
	public void run() {
		for(int i=0; i<5; i++)
			data.up();
	}
}
 

① 4행: UpDown 클래스에서 data를 호출

② 6행: UpThread 생성자

③ 11행: run() 메소드 오버라이딩

 

(3) DownThread.java

package com.thread;

public class DownThread extends Thread{
	UpDown data;

	public DownThread(UpDown data) {
		super();
		this.data = data;
	}
	
	public void run() {
		for(int i=0; i<5; i++)
			data.down();
	}
}
 

① 4행: UpDown 클래스에서 data를 호출

② 6행: DownThread 생성자

③ 11행: run() 메소드 오버라이딩

 

(4) UpDownTest.java (main)

package com.thread;

public class UpDownTest {

	public static void main(String[] args) {
		UpDown updown = new UpDown(0);
		UpThread up = new UpThread(updown);
		DownThread down = new DownThread(updown);
		
		up.start();
		down.start();
	}
}
 

① 7행: UpThread의 생성자로 들어가 this.data = data; 실행

② 8행: DownThread의 생성자로 들어가 this.data = data; 실행

 

[결과화면]

* 증가, 감소가 순차적이지 않고 시분할 (Thread)


0. Synchronized: 동기화 > 임계 영역을 잡아 주는 것

1. notifyAll(): wait()에 의해 중지된 메소드를 실행 모드로 변경

2. wait(): 실행 중인 메소드를 중지 (<->notify)

(1) UpDown 클래스만 수정

package com.thread;

public class UpDown {
	int data;
	
	public UpDown(int data) {
		super();
		this.data = data;
	}

	public synchronized void up() {
		if(data>=3) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		data++;
		System.out.println("증가 " + data);
		notifyAll();
	}
	
	public synchronized void down() {
		if(data<=0)
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		data--;
		System.out.println("감소 " + data);
		notifyAll();
	}
}
 

① 14행: wait(): 값이 3이상이면 스레드 중지 (4가 넘을 수 없음)

② 21행: notifyAll(): down()메소드를 실행하라

③ 27행: wait(): 값이 0이하이면 스레드 중지 (음수가 될 수 없음)

④ 33행: notifyAll(): up()메소드를 실행하라

 

[결과화면]

* (0~3)사이의 값만 나옴


(3) join(): 실행 중지 시켰다가 나중에 실행

package com.thread;

public class Multiplication extends Thread {
int input;

public Multiplication(int input) {
	super();
	this.input = input;
}

public void run() {
	if(this.input == 5)
		try {
			join(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	for(int i=1; i<=9; i++) {
		System.out.println(this.input + " * " + i + " = " + (this.input*i));
	}	
}
}
 
package com.thread;

public class InputTest {
	public static void main(String[] args) {
		Multiplication result5 = new Multiplication(5);
		result5.start();
	}
}
 

[결과화면]

* 5초 후에 5단 구구단이 출력됨

 


 

'STUDY > Java' 카테고리의 다른 글

[JAVA] Collection (List, Set, Map)  (0) 2021.11.05
[JAVA] Generic 제네릭  (0) 2021.11.05
[JAVA] 예외처리  (0) 2021.11.05
[JAVA] 정렬, 익명클래스  (0) 2021.11.05
[JAVA] 데이터 타입 - 기본타입, 참조타입  (0) 2021.11.05