Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 스프링 입문(무료)
- 자바의 정석 기초편 ch8
- 자바의 정석 기초편 ch7
- 자바의 정석 기초편 ch1
- 스프링 mvc1 - 스프링 mvc
- 자바의 정석 기초편 ch3
- 자바의 정석 기초편 ch6
- 2024 정보처리기사 시나공 필기
- 자바의 정석 기초편 ch4
- 스프링 db2 - 데이터 접근 기술
- 스프링 mvc2 - 검증
- 자바의 정석 기초편 ch2
- 스프링 mvc2 - 로그인 처리
- 스프링 db1 - 스프링과 문제 해결
- 게시글 목록 api
- 코드로 시작하는 자바 첫걸음
- 스프링 고급 - 스프링 aop
- 자바의 정석 기초편 ch14
- jpa 활용2 - api 개발 고급
- 자바의 정석 기초편 ch9
- 스프링 mvc2 - 타임리프
- 자바의 정석 기초편 ch12
- 스프링 mvc1 - 서블릿
- jpa - 객체지향 쿼리 언어
- 타임리프 - 기본기능
- 자바의 정석 기초편 ch13
- 자바의 정석 기초편 ch11
- @Aspect
- 2024 정보처리기사 수제비 실기
- 자바의 정석 기초편 ch5
Archives
- Today
- Total
나구리의 개발공부기록
자바의 정석 기초편 ch13 - 22 ~ 29 [sleep(), interrupt(), suspend(), resume(), stop(),join(),yield()] 본문
유튜브 공부/JAVA의 정석 기초편(유튜브)
자바의 정석 기초편 ch13 - 22 ~ 29 [sleep(), interrupt(), suspend(), resume(), stop(),join(),yield()]
소소한나구리 2023. 12. 18. 16:511) static void sleep()
- 자기자신에게 동작하며 현재 쓰레드를 지정된 시간동안 멈추게 함
- 예외처리를 필수로 해야하며 InterruptedException이 발생하면 깨어남
- 특정 쓰레드를 지정해서 멈추게 하는 것은 불가능하며 자기자신의 쓰레드만 적용
// 코드 예시
static void sleep(long millis) // 천분의 일초 단위 1000 = 1초
static void sleep(long millis, int nanos) // 천분의 일초 + 나노초(10의 -9제곱)
// 예외처리 항상 필수
try {
Thread.sleep(1, 500000); // 쓰레드를 0.0015초 동안 멈추게 한다
} catch(InterruptedException e) {} // Exception의 자손 -> 예외 필수 처리
// 항상 예외처리를 하는 것이 불편하니 메서드를 만들어서 메서드 호출로 사용
void delay(long millis) {
try {
Thread.sleep(millis);
} catch(InterruptedException e) {}
---
delay(15); // 메서드를 만들어서 호출하여 사용
// 특정 쓰레드 지정 불가(코드 오해)
try {
th1.sleep(10000); // 에러는 나지 않으나 th1이라는 쓰레드를 잠자기 하는걸로 오해 할 수 있음
} catch(InterruptedException e) {}
try {
Thread.sleep(10000); // 오해가 없도록 항상 이렇게 코드 작성 권장
} catch(InterruptedException e) {}
(1) 예제
- 2초동안 멀티쓰레드가 동작하여 프로그램이 실행되고 종료 됨
class Ex13_8 {
public static void main(String args[]) {
runThread1 th1 = new runThread1();
runThread2 th2 = new runThread2();
th1.start();
th2.start();
delay(2*1000); // 2초 대기
System.out.print("<<main 종료>>");
} // main
static void delay(long millis) { // sleep을 메서드로 작성
try {
Thread.sleep(millis); // 2초동안 잠자기, try - catch문 필수(예외처리 필수)
} catch(InterruptedException e) {}
}
}
class runThread1 extends Thread {
public void run() {
for(int i=0; i < 300; i++) System.out.print("-");
System.out.print("<<th1 종료>>");
} // run()
}
class runThread2 extends Thread {
public void run() {
for(int i=0; i < 300; i++) System.out.print("|");
System.out.print("<<th2 종료>>");
} // run()
}
2) interrupt()
- 쓰레드를 깨워서 대기상태(WAITING)인 쓰레드를 실행대기 상태(RUNNABLE)로 만듦
- sleep(), join(), wait()등의 메서드로 작업이 중단된 쓰레드를 interrupt()로 실행대기 상태로 전환함
- 어떤 작업을 하다가 쓰레드의 작업을 중단시키고 싶을때, 중단 된 작업을 다시 작업시키고 싶을 때 사용
- isInterrupted()로 쓰레드가 interrupted상태인지를 확인할 수 있음
interrupt() // 쓰레드의 interrupted상태를 false에서 true로 변경
boolean isInterrupted() // 쓰레드의 interrupted상태를 반환 -> 상태 유지
static boolean interrupted() // 현재 쓰레드의 interrupted상태를 알려줌 -> false로 변경
class Thread { // Thread 클래스의 구성을 알기쉽게 재구성
...
boolean interrupted = false; // interrupted의 기본상태는 false
...
boolean isInterrupted() { // 현재상태를 반환하는 isInterrupted()가 정의되어있음
return interrupted;
}
boolean interrupt() { // interrupted를 true로 변경하는 interrupt()가 정의되어있음
interrupted = true;
}
}
(1) 예제
- 카운트다운 실행 종료 -> 쓰레드 상태 확인 출력
- interrupted()는 static 메서드이므로 자기 자신의 상태를 출력
- 아래 예제 중 main 메서드안에서 interrupted()를 호출하면 th1의 상태를 확인 하는 것이 아니라 main메서드의 상태를 확인함 -> 헷갈리지 않도록 Thread.interrupted()로 호출
import javax.swing.JOptionPane;
class Ex13_9 {
public static void main(String[] args) throws Exception {
countThread th1 = new countThread();
th1.start();
// interrupt()호출 전 isInterrupted는 false
System.out.println("isInterrupted():"+ th1.isInterrupted());
String input = JOptionPane.showInputDialog("아무 값이나 입력하세요.");
System.out.println("입력하신 값은 " + input + "입니다.");
th1.interrupt(); // interrupt()를 호출하면, interrupted의 상태가 true가 됨
// isInterrupted()로 상태를 계속 확인하면 상태는 true
System.out.println("isInterrupted():"+ th1.isInterrupted()); // true
System.out.println("isInterrupted():"+ th1.isInterrupted()); // true
// 여기서 interrupted()를 호출하면 main쓰레드의 쓰레드 상태를 확인하는 것이 됨
// main메서드는 interrupt()가 호출된 적이 없어서 false가 나옴
// th1의 쓰레드의 상태 확인은 run()에서 interrupted()를하거나 th1.isInterrupted()로 확인해야함
// System.out.println("interrupted():"+ interrupted()); //false
// System.out.println("interrupted():"+ Thread.interrupted()); //false
}
}
class countThread extends Thread { // 카운트다운 메서드
public void run() {
int i = 10;
// isInterrupted()가 false 이거나 0이 아닐 때 반복문을 실행
while(i!=0 && !isInterrupted()) {
System.out.println(i--);
for(long x=0;x<2500000000L;x++); // 시간 지연
}
// isInterrupted()로 쓰레드의 상태를 확인 확인 -> 확인후에도 상태가 유지됨
// this.을 제외해도 됨
System.out.println("isInterrupted():"+this.isInterrupted()); // true
System.out.println("isInterrupted():"+isInterrupted()); // true
// interrupted()로 쓰레드의 상태를 확인 -> 확인 후에 상태를 false로 변경함
// Thread.을 제외해도 됨
System.out.println("isInterrupted():"+ interrupted()); // true
System.out.println("isInterrupted():"+ Thread.interrupted()); // false 로 초기화
// isInterrupted()가 true 이면 반복문이 바로 종료됨
System.out.println("카운트가 종료되었습니다.");
}
}
3) 정지, 일시정지, 재개
- 아래의 쓰레드들은 deadlock(교착상태)를 일으키기가 쉽기 때문에 deprecated(사용을 권장하지 않음)되었음
- 그래도 사용할 수는 있고, 직접 구현해서 사용도 가능함
(1) suspend()
- 쓰레드를 일시정지
(2) resume()
- 일시정지된 쓰레드를 재개
(3) stop()
- 완전정지, 쓰레드를 즉시 종료
// 간단히 코드를 직접 구성하는 틀 예제, 실제로는 더 복잡함
class ThreadEx17_1 implements Runnable {
boolean suspended = false; // 일시정지인지 확인
boolean stopped = false; // 정지되었는지 확인
public void run() { // 멀티쓰레드 실행 메서드
while(!stopped) { // stoppend = true이면
if(!suspended){ // suspended = true이면
/* 작업을 수행할 코드를 작성 */ 코드를 수행
}
}
}
public void suspend() { suspended = true; } // suspend()호출
public void resume() { suspended = false; } // resume()호출
public void stop() { stop = true; } // stop()호출
}
(4) 예제
class Ex13_10 {
public static void main(String args[]) {
MyThread th1 = new MyThread("*");
MyThread th2 = new MyThread("**");
MyThread th3 = new MyThread("***");
th1.start();
th2.start();
th3.start();
// deprecated 되었지만 직접 구현하면 deprecated표시가 사라짐
try {
Thread.sleep(2000);
th1.suspend(); // 쓰레드 th1을 잠시 중단
Thread.sleep(2000);
th2.suspend(); // 쓰레드 th2를 잠시 중단
Thread.sleep(3000);
th1.resume(); // 쓰레드 th1이 다시 동작
Thread.sleep(3000);
th1.stop(); // 쓰레드 th1을 강제종료
th2.stop(); // 쓰레드 th2을 강제종료
Thread.sleep(2000);
th3.stop(); // 쓰레드 th3을 강제종료
} catch (InterruptedException e) {}
} // main
}
// suspend,stop메서드를 직접 구현해보기
class MyThread implements Runnable {
// volatile(쉽게 바뀌는 변수) - 자바의 정석 3판에서 자세히 설명
volatile boolean suspended = false; // volatile - 복사본 사용 금지(캐시메모리에 원본을 사용)
volatile boolean stopped = false; // 실행시 종료가 안될 경우 volatile를 붙히면 됨
Thread th;
MyThread(String name) {
th = new Thread(this, name); // Thread(Runnable r, String name)
}
void start() {
th. start();
}
void stop() {
stopped = true;
}
void suspend() {
suspended = true;
}
void resume() {
suspended = false;
}
public void run() {
while(!stopped) {
if(!suspended) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
}
}
} // run()
}
4) join()
- 지정된 시간동안 특정 쓰레드가 작업하는 것을 기다림
- 예외처리를 해야하며 InterruptedException이 발생하면 깨어남
void join() // 작업이 모두 끝날때까지
void join(long millis) // 천분의 일초 동안
void join(long millis, int nanos) // 천분의 일초 + 나노초 동안
(1) 예제
- 쓰레드1과 쓰레드2의 작업시간을 알기 위해 작업이 끝날 때까지 기다렸다가 실행
class Ex13_11 {
static long startTime = 0;
public static void main(String args[]) {
ThreadEx11_1 th1 = new ThreadEx11_1();
ThreadEx11_2 th2 = new ThreadEx11_2();
th1.start();
th2.start();
startTime = System.currentTimeMillis(); // 시작시간
try { // 예외처리
th1.join(); // main쓰레드가 th1의 작업이 끝날 때까지 기다린다.
th2.join(); // main쓰레드가 th2의 작업이 끝날 때까지 기다린다.
} catch(InterruptedException e) {}
// 종료시간 - 시작시간
System.out.print("소요시간:" + (System.currentTimeMillis() - Ex13_11.startTime));
} // main
}
class ThreadEx11_1 extends Thread {
public void run() {
for(int i=0; i < 700; i++) {
System.out.print(new String("-"));
}
} // run()
}
class ThreadEx11_2 extends Thread {
public void run() {
for(int i=0; i < 700; i++) {
System.out.print(new String("|"));
}
} // run()
}
(2) 추가 예제
- 가비지컬렉터를 흉내내는 예제 (가비지컬렉터는 데몬쓰레드 - 보조쓰레드)
- 메모리부족이 발생하면 join()으로 gc메서드가 작업할 시간을 부여 후 정리가 되면 메모리를 사용하도록 동작
package ch13;
class GCMemoryManagementExample implements Runnable {
private long usedMemory = 0;
public void run() {
while (true) {
try {
Thread.sleep(10 * 1000); // 10초를 기다림
} catch (InterruptedException e) {
System.out.println("Awaken by interrupt().");
}
System.gc(); // garbage collection를 수행
System.out.println("Garbage Collected. Free Memory: " + freeMemory());
for (int i = 0; i < 20; i++) {
long requiredMemory = (long) (Math.random() * 10) * 20;
// 힙의 메모리가 사용될 수 있는 양보다 작거나 전체 메모리의 60%이상 사용했을 경우 gc를 개시
if (freeMemory() < requiredMemory || usedMemory() > totalMemory() * 0.4) {
System.gc(); // 작업 중인 스레드 gc를 개시
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
usedMemory += requiredMemory;
System.out.println("usedMemory:" + usedMemory);
}
}
}
private long freeMemory() {
return Runtime.getRuntime().freeMemory();
}
private long totalMemory() {
return Runtime.getRuntime().totalMemory();
}
private long usedMemory() {
return totalMemory() - freeMemory();
}
public static void main(String[] args) {
Thread t = new Thread(new GCMemoryManagementExample());
t.start();
}
}
5) yield()
- 남은 시간을 다음 쓰레드에게 양보하고 자신은 실행대기
- yield()와 interrupt()를 적절히 사용하면 응답성과 효율을 높일 수 있음.
- yield는 JVM스케줄러에게 통보(JVM스케줄러가 OS스케줄러에게 통보)하는 것이기 때문에 반드시 즉시 동작한다고 보장하기는 어려움
(1) 예제
package ch13;
public class MyThreadEx18 implements Runnable {
private boolean suspended = false;
private boolean stopped = false;
private Thread th;
public MyThreadEx18(String name) {
th = new Thread(this, name);
}
public void run() {
while (!stopped) {
if (!suspended) {
// 작업 수행
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
} else {
Thread.yield(); // suspended의 상태가 true이면 실행순서를 양보
}
}
}
public void start() {
th.start();
}
public void resume() {
suspended = false;
}
public void suspend() {
suspended = true;
th.interrupt();
}
public void stop() {
stopped = true;
th.interrupt();
}
}
** 출처 : 남궁성의 정석코딩_자바의정석_기초편 유튜브
'유튜브 공부 > JAVA의 정석 기초편(유튜브)' 카테고리의 다른 글
자바의 정석 기초편 ch14 - 1 ~ 6 [람다식이란?, 람다식 작성하기, 함수형 인터페이스] (0) | 2023.12.19 |
---|---|
자바의 정석 기초편 ch13 - 33 ~ 36 [쓰레드의 동기화, wait(), notify()] (0) | 2023.12.19 |
자바의 정석 기초편 ch13 - 14 ~ 21 [쓰레드의우선순위,쓰레드그룹,데몬쓰레드, 쓰레드의 상태] (1) | 2023.12.18 |
자바의 정석 기초편 ch13 - 1 ~ 13 [쓰레드,쓰레드의 구현과 실행, 싱글 쓰레드와 멀티쓰레드, 쓰레드의 I/O블로킹] (1) | 2023.12.15 |
자바의 정석 기초편 ch12 - 23 ~ 37 [애노테이션, 표준애노테이션, 메타애노테이션, 애노테이션 타입 정의하기, 애노테이션의 요소] (0) | 2023.12.15 |