1. Thread란?
프로세스 안에서 실질적으로 작업을 실행하는 단위
프로세스에는 적어도 한 개 이상의 Thread가 있다.
main Thread 하나에서 Thread를 추가 생성하게 되면 멀티 Thread 환경이 된다.
2. Thread의 생성자
1) Thread
- Thread() : 새로운 스레드 객체 할당
- Thread(String name) : 새로운 스레드 객체가 할당되며, 스레드 이름은 name으로 설정됨
- Thread(Runnable target) : Runnable target이 구현된 스레드 객체 할당
- Thread(Runnable target, String name) : Runnable target이 구현된 스레드 객체가 할당되면 스레드 이름은 name으로 설정됨
3. Thread를 사용하면 좋은 상황 👍
- 동시에 해야할 때
- I/O가 일어날 때
4. Thread 생성 방법
- Thread 클래스를 상속 받는 방법
- Runnable 인터페이스를 구현하는 방법
5. Thread 기본 1
package ex19;
// 스레드 기본 (스레드 객체 생성, 스레드 시작, 타겟(run메소드) 만들기)
public class Th01 {
public static void sub1() {
for (int i = 1; i <= 5; i++) {
System.out.println("스레드 1 : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public static void sub2() {
for (int i = 1; i <= 5; i++) {
System.out.println("스레드 2 : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
// class SSS implements Runnable {
// public void run() {
// }
// }
public static void main(String[] args) { // cpu -> 메인 쓰레드
Thread t1 = new Thread(() -> sub1()); // 한 줄이면 중괄호 생략 가능, run메소드 = (() -> sub1()), 타겟은 run
t1.start();
new Thread(() -> sub2() // 타겟은 run
).start();
}
}

6. Thread 기본 2
package ex19;
public class Th02 {
static String product = null;
public static void main(String[] args) {
Thread supp = new Thread(() -> {
try {
Thread.sleep(10000);
product = "바나나깡";
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
supp.start();
Thread lis = new Thread(() -> {
while (true) {
try {
Thread.sleep(500);
if (product != null) {
System.out.println("상품이 입고되었습니다. : " + product);
break;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
lis.start();
}
}
7. Thread 동시 작업 처리 예제
package ex19;
class MyFile {
public void write() {
try {
Thread.sleep(5000);
System.out.println("파일 쓰기 완료");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
class 화가 {
public void 그림그리기() {
System.out.println("그림 그리기 완료");
}
}
// 화가
public class Th03 {
public static void main(String[] args) {
MyFile myFile = new MyFile();
화가 painter = new 화가();
painter.그림그리기();
new Thread(() -> {
myFile.write();
}).start();
painter.그림그리기();
}
}
8. Class로 Thread 만들기
package ex19;
import java.util.ArrayList;
import java.util.List;
// 1. 상속받고 2. 타겟 재정의
class MyThread extends Thread {
private List<Integer> list;
@Override
public void run() { // 타겟 재정의
for (int i = 0; i < 10; i++) {
System.out.println("MyThread : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public MyThread(List<Integer> list) {
this.list = list;
}
public void addList(int num) {
list.add(num);
}
public List<Integer> getList() {
return list;
}
}
// 클래스로 스레드 만들기 (스레드별 상태 보관)
public class Th04 {
public static void main(String[] args) {
MyThread t1 = new MyThread(new ArrayList<>()); // MyThread는 ArrayList에 의존한다.
t1.start();
}
}
9. Thread 숫자 카운터 프로그램 예제
package ex19;
import javax.swing.*;
public class Th05 extends JFrame { // JFrame = 자바에서 그림그리는 도구
private boolean state = true;
private int count = 0;
private int count2 = 0;
private JLabel countLabel;
private JLabel count2Label;
public Th05() {
setTitle("숫자 카운터 프로그램");
setVisible(true);
setSize(300, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 레이아웃 매니저 설정
setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
// 숫자를 표시할 레이블 생성
countLabel = new JLabel("숫자1: " + count);
count2Label = new JLabel("숫자2: " + count2);
countLabel.setAlignmentX(CENTER_ALIGNMENT);
count2Label.setAlignmentX(CENTER_ALIGNMENT);
add(countLabel);
add(count2Label);
// 멈춤 버튼 생성
JButton increaseButton = new JButton("멈춤");
increaseButton.setAlignmentX(CENTER_ALIGNMENT);
add(increaseButton);
// 버튼에 액션 리스너 추가
increaseButton.addActionListener(e -> {
state = false;
});
new Thread(() -> {
while (state) {
try {
Thread.sleep(1000);
count++;
countLabel.setText("숫자1 : " + count);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}).start();
new Thread(() -> {
while (state) {
try {
Thread.sleep(1000);
count2++;
count2Label.setText("숫자2 : " + count2);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}).start();
}
public static void main(String[] args) {
new Th05();
}
}
10. Thread가 return해야 할 때 (첫번째 방법)
package ex19;
//콜백
class Store implements Runnable {
int qty;
@Override
public void run() {
// 통신 -> 다운로드
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
qty = 5;
}
}
/*
스레드에서 받은 데이터를 리턴 받아서 응용하고 싶을때!!
1. 타이밍 맞추기 (임시방편 - 그래도 쓰는 사람 많음)
2. 리스너 (부하가 너무 큼)
3. 콜백 (제일 좋음)
*/
// 사용 이유 : 동시에 해야할 때, I/O가 일어날 때!!
public class Th06 {
public static void main(String[] args) {
int totalQty = 10;
Store store = new Store();
Thread t1 = new Thread(store);
t1.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("재고수량 :" + (store.qty + totalQty));
}
}
11. Thread가 return해야 할 때 (두번째 방법)
package ex19;
//콜백
class Store implements Runnable {
Integer qty;
@Override
public void run() {
// 통신 -> 다운로드
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
qty = 5;
}
}
/*
스레드에서 받은 데이터를 리턴 받아서 응용하고 싶을때!!
1. 타이밍 맞추기 (임시방편 - 그래도 쓰는 사람 많음)
2. 리스너 (부하가 너무 큼)
3. 콜백 (제일 좋음)
*/
// 사용 이유 : 동시에 해야할 때, I/O가 일어날 때!!
public class Th06 {
public static void main(String[] args) {
int totalQty = 10;
Store store = new Store();
Thread t1 = new Thread(store);
t1.start();
while (true) {
if (store.qty != null) break;
try {
Thread.sleep(10);
System.out.println(store.qty + "지켜본다");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("재고수량 :" + (store.qty + totalQty));
}
}

12. Thread 콜백 메소드 활용
package ex19;
//콜백
// [1] 콜백 메소드 만들기
interface Callback {
void 입고(int qty); // 괄호 안에는 리턴 받고 싶은 인수를 만들어주면 된다. = 정확하게는 파라미터
}
class Store implements Runnable {
// [2] 리턴이 필요한 곳으로 가서 콜백 메소드 전달 받기
Integer qty;
Callback callback;
public Store(Callback callback) {
this.callback = callback;
}
@Override
public void run() {
// 통신 -> 다운로드
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
qty = 5;
callback.입고(qty); // [3] 종료시 콜백 메소드 호출
}
}
/*
스레드에서 받은 데이터를 리턴 받아서 응용하고 싶을때!!
1. 타이밍 맞추기 (임시방편 - 그래도 쓰는 사람 많음)
2. 리스너 (부하가 너무 큼)
3. 콜백 (제일 좋음)
*/
// 사용 이유 : 동시에 해야할 때, I/O가 일어날 때!!
public class Th06 {
public static void main(String[] args) {
int totalQty = 10;
Store store = new Store(qty -> {
System.out.println("재고수량 :" + (qty + totalQty));
});
Thread t1 = new Thread(store);
t1.start();
}
}

Share article