[혼공학습단 10기☕️] 자바 week4
미션
기본미션 : p. 550 [직접 해보는 손코딩] 코딩 과정 및 실행 결과 캡처하기
// AutoSaveThread.java
package sec02.exam05;
public class AutoSaveThread extends Thread{
public void save() {
System.out.println("작업 내용을 저장함.");
}
@Override
public void run() {
while (true)
{
try {
Thread.sleep(1000);
} catch(Exception e) {
break;
}
save();
}
}
}
// DaemonExample.java
package sec02.exam05;
public class DaemonExample {
public static void main(String[] args) {
AutoSaveThread autoSaveThread = new AutoSaveThread();
autoSaveThread.setDaemon(true);
autoSaveThread.start();
try {
Thread.sleep(3000);
} catch(Exception e) {
}
System.out.println("메인 스레드 종료");
}
}
선택미션 : p. 539 문제 2번 풀고, 풀이 과정 설명하기
// ThreadExample.java
package sec01.verify.exam02;
public class ThreadExample {
public static void main(String[] args) {
Thread thread1 = new MovieThread();
thread1.start();
Thread thread2 = new Thread(new MusicRuunable());
thread2.start();
}
}
- ① new MusicRuunable()
- Thread 클래스로부터 작업 스레드 객체를 생성하기 위해서는 Runnable을 매개값으로 갖는 생성자를 호출해야 함
- 따라서 MusicRunnable 구현 객체를 생성하고 이를 매개값으로 Thread 생성자를 호출
// MovieThread.java
package sec01.verify.exam02;
public class MovieThread extends Thread {
@Override
public void run() {
for (int i=0; i<3; i++){
System.out.println("동영상을 재생합니다.");
try {Thread.sleep(1000);} catch(Exception e) {}
}
}
}
- ② extends Thread
- 작업 스레드가 실행할 작업을 Runnable로 만들지 않고 Thread의 하위 클래스로 작업 스레드를 정의하면서 작업 내용을 포함시킬 수도 있음 -> Thread 클래스를 상속
// MusicRuunable.java
package sec01.verify.exam02;
public class MusicRuunable implements Runnable{
@Override
public void run() {
for (int i=0; i<3; i++){
System.out.println("음악을 재생합니다.");
try {Thread.sleep(1000);} catch(Exception e) {}
}
}
}
- ③ implements Runnable
- Runnable 구현 클래스를 작성
Chapter 12 스레드
1. 멀티 스레드
📍프로세스 : 운영체제에서 실행 중인 하나의 애플리케이션
📌 스레드
- 운영체제는 두 가지 이상의 작업을 동시에 처리하는 멀티 태스킹을 할 수 있도록 CPU 및 메모리 자원을 프로세스마다 적절히 할당해주고, 병렬로 실행시킨다.
- 멀티 프로세스는 자신의 메모리를 가지고 실행하므로 서로 독립적이다.
- 멀티 스레드는 하나의 프로세스 내부에 생성된다.
📌 메인 스레드
- 자바의 모든 애플리케이션은 메인 스레드가 main() 메소드를 실행하면서 시작된다.
- 메인 스레드는 필요에 따라 멀티 스레드를 생성해서 멀티 태스킹을 수행한다.
📌 작업 스레드 생성과 실행
- Thread 클래스로부터 직접 생성
- Runnable을 매개값으로 갖는 생성자 호출
Runnable task = new Task();
Thread thread = new Thread(Runnable target);
- Runnable은 인터페이스 타입이기 때문에 구현객체를 만들어 대입해야 함.
- Runnable에 run() 메소드가 정의되어 있는데 구현클래스는 run()을 재정의해서 작업 스레드가 실행할 코드를 작성해야 함.
class Task implements Runnable {
public void run() {
// 스레드가 실행할 코드;
}
}
- Thread 생성자를 호출할 때 Runnable 익명 객체를 매개값으로 사용할 수 있다.
Thread thread = new Thread(new Runnable() {
public void run() {
// 스레드가 실행할 코드;
}
});
- 작업 스레드는 생성되는 즉시 실행되는 것이 아니라, start() 메소드를 호출해야 함.
thread.start();
- Thread 하위 클래스로부터 생성
- 작업 스레드가 실행할 작업을 Runnable로 만들지 않고, Thread의 하위 클래스로 작업 스레드를 정의하면서 작업 내용을 포함시킬 수 있음.
public class WorkerThread extends Thread {
@Override
public void run() {
// 스레드가 실행할 코드;
}
}
Thread thread = new WorkerThread();
- Thread 익명 객체로 작업 스레드 객체를 생성할 수 있다.
Thread thread = new Thread() {
public void run() {
// 스레드가 실행할 코드;
}
}
- 스레드의 이름
- 스레드의 이름이 큰 역할을 하는 것은 아니지만, 디버깅할 때 어떤 스레드가 어떤 작업을 하는지 조사할 목적으로 사용하기도 함.
- 메인 스레드는 'main'이라는 이름을 가지고 있고, 생성한 스레드는 자동적으로 이름이 'Thread-n'으로 설정된다. (n은 스레드의 번호)
- 이름을 직접 설정하고 싶다면 Thread 클래스의 setName() 메소드로 변경할 수 있다.
- 스레드의 이름을 알고 싶을 때는 getName() 메소드를 호출하면 된다.
- setName(), getName()은 Thread 클래스의 인스턴스 메소드이므로 스레드 객체의 참조가 필요하다.
- 현재 스레드객체의 참조를 가지고 있지 않다면 currentThread()를 이용해서 현재 스레드의 참조를 얻을 수 있다.
Thread thread = Thread.currentThread();
thread.setName("스레드 이름");
thread.getName();
📌 동기화 메소드
- 공유 객체 사용 시 주의점 : 하나의 스레드가 사용하던 객체를 다른 스레드가 접근 가능하므로 원치 않은 결과 초래 가능
- 동기화 메소드
- 스레드가 사용 중인 객체를 다른 스레드가 변경할 수 없도록 스레드 작업이 끝날 때까지 객체에 잠금을 걸어야 함.
- 임계 영역 : 멀티 스레드 프로그램에서 단 하나의 스레드만 실행할 수 있는 코드 영역
- 동기화 메소드 : 임계 영역을 지정하기 위해 사용
public synchronized void method() {
// 임계 영역;
}
2. 스레드 제어
📌 스레드 상태
- 스레드 객체를 생성하고 start() 메소드를 호출하면 실행 대기 상태가 된다.
- 실행 대기 상태에 있는 스레드 중에서 운영체제는 하나의 스레드를 선택하고 CPU가 run() 메소드를 실행하도록 하면 실행 상태가 된다.
- 스레드는 실행 대기 상태와 실행 상태를 번갈아가면서 run() 메소드를 조금씩 실행한다.
- 실행 상태에서 run() 메소드가 종료되면 종료 상태가 된다.
- 스레드가 실행될 수 없는 상태를 일시 정지 상태라고 한다.
📌 스레드 상태 제어
- 스레드 상태 제어 : 실행 중인 스레드의 상태를 변경하는 것
- 상태를 변화시키는 메소드의 종류
- interrupt() : 일시 정지 상태의 스레드에서 InterruptedException을 발생시켜, 예외 처리 코드에서 실행 대기 상태나 종료 상태로 갈 수 있음.
- sleep(long millis) : 주어진 시간 동안 스레드를 일시 정지 상태로 만듦. 주어진 시간이 지나면 자동으로 실행 대기 상태가 됨.
- stop() : 스레드를 즉시 종료. 불안정한 종료를 유발하므로 사용하지 않는 것이 좋음.
- 주어진 시간 동안 일시 정지 : sleep()
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
// interrupt() 메소드가 호출되면 실행
}
- 스레드의 안전한 종료 : 실행 중인 스레드를 즉시 종료하기
① stop 플래그 이용
public class XXXThread extends Thread{
private boolean stop; // stop 플래그 빌드
public void run() {
while (!stop) {
// 스레드가 반복실행하는 코드
}
// 스레드가 사용한 자원 정리
}
}
② interrupt() 메소드 이용
- 일시 정지 상태의 스레드에서 InterruptedException을 발생시켜, 예외 처리 코드 블록으로 이동
- 스레드가 실행 대기 또는 실행 상태에 있을 때 interrupt() 메소드가 실행되면 즉시 InterruptedException이 발생하지 않고 스레드가 일시 정지 상태일 때 발생
- 일시 정지를 만들지 않고 interrupt()의 호출 여부를 알기 위해 interrupted()나 isInterrupted() 메소드 사용 가능
boolean status = Thread.interrupted();
boolean status = objThread.isInterrupted();
📌 데몬 스레드
- 주 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드
- 주 스레드가 종료되면 데몬 스레드는 강제 종료됨.
- 스레드를 데몬 스레드로 만들기 위해서는 주 스레드가 데몬이 될 스레드의 setDaemon(true)를 호출한다.
public static void main(String[] args) {
AutoSaveThread thread = new AutoSaveThread();
thread.setDaemon(true);
thread.start();
}
스레드는 처음이라 많이 어려웠습니다.... 다음 주는 쉬어가는 주이니 열심히 복습해서 돌아오겠습니다💪
+) 여담
족장님 제가 2주차 우수혼공족이라서 받은 기프티콘으로 바닐라 아메리카노 먹어봤는데 맛있어요!! 아이스 바닐라 라떼와 아메리카노 사이 느낌입니다..ㅎㅎ 우수혼공족으로 받은 기프티콘 사용하면서 열심히 공부 중입니다😍