답답해서 공부해보는 thread...자바의 정석 책을 다시 펼쳤다..
◼️쓰레드 구현과 실행
🟢 쓰레드 구현 방법 두가지
- Thread클래스를 상속 (단점: 다른클래스 상속받을수없음)
- Runnable인터페이스를 구현
//1.Thread 클래스를 상속
class MyThread extends Thread{
public void run() { /*작업내용*/ }
}
//2.Runnable 인터페이스를 구현
class MyRunnable implements Runnable{
public void run() { /*작업내용*/ }
}
🔶예시 코드
public class ThreadEx1 {
public static void main(String[] args) {
ThreadEx1_1 t1 = new ThreadEx1_1();
Runnable r = new ThreadEx1_2(); //Runnable 인터페이스를 구현한 클래스의 인스턴스를 생성
Thread t2 = new Thread(r); // 생성자 Thread(Runnable target)
t1.start();
t2.start();
//쓰레드의 작업을 한 번 더 수행해야 할 시 새로운 쓰레드를 생성해야한다.
//t1.start(); //IllegalthreadStateException 발생
}
}
class ThreadEx1_1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
// 조상인 thread getName 호출
System.out.println(getName());
}
}
}
class ThreadEx1_2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
// 현재 실행중인 Thread 반환
System.out.println(Thread.currentThread().getName());
}
}
}
◼️start(), run()
근데 한가지 의문이든다. 위 코드에서 왜 run()이 아니라 start()를 호출할까?
🟢run() vs start()
- run(); 쓰레드실행이아닌 단순 선언 메서드를 호출하는것이다.
- start(); 새로운 쓰레드가 작업을 실행하는데 필요한 호출스택(call stack)을 생성 후 run()을 호출한다. 따라서 생성호출스택에 run()이 첫번째로 올라가게 된다.
이때 호출스택에선 최상위 메서드라도 실행중이 아닌 '대기상태'에 있을 수 있다.
스케줄러는 실행대기중인 쓰레드들의 우선순위를 고려해 실행순서와 실행시간을 결정한다.
참고로 당연히, main 메서드를 수행하는 것도 쓰레드이다.이때 실행 중인 사용자 쓰레드가 하나도 없을 때 프로그램은 종료된다.예를들어 아래처럼 쓰레드를 시작할때 throwException 예외를 발생시켜보자.
public class ThreadEx2 {
public static void main(String[] args) {
System.out.println("main 스레드 시작");
ThreadEx2_1 t1 = new ThreadEx2_1();
t1.start();
System.out.println("main 스레드 종료");
}
}
class ThreadEx2_1 extends Thread {
@Override
public void run() {
throwException();
}
public void throwException() {
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
}
start()로 호출했기에 main 스레드와 t1 쓰레드가 독립적으로 실행된다. 한 쓰레드가 예외발생으로 종료되어도, 다른 쓰레드엔 전혀 영향을 미치지않는다. 여기서 main쓰레드는 이미 종료되었기 때문에 호출스택이 없다.
public class ThreadEx3 {
public static void main(String[] args) {
System.out.println("main 스레드 시작");
ThreadEx3_1 t1 = new ThreadEx3_1();
t1.run();
System.out.println("main 스레드 종료");
}
}
class ThreadEx3_1 extends Thread {
@Override
public void run() {
throwException();
}
public void throwException() {
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
}
이전과 달리 위는 run() 메서드가 main 스레드에서 실행된다. 즉, 새로운 쓰레드가 생성되지 않는다. 호출스택에도 main이 포함되어있다.
??모르겟는것
동일한 콜스택에있으면 main스레드종료 출력문이 exception 후에 떠야되는거아닌가?; 잘모르겟음
==>아하! printStackTrace와 일반출력은 서로 아예 다른 파이프이기때문에 출력순위가 보장X!!!!
◼️싱글 코어, 멀티 코어 비교
싱글 코어는 한개의 코어가 두가지 일을 진행하므로 겹칠 일이 없다.
반면 멀티 코어는 두 스레드 작업이 동시에 수행될 수 있으므로 작업이 겹칠 수 있는데, 이때 쓰레드 경쟁이 일어날 수도 있다.
예를들어 console 자원을 놓고 두 쓰레드가 경쟁할 수 있는 것이다.
🟢정리
- 싱글코어에서 단순 계산 작업은 싱글스레드가 더 효율적이다.
- 이유: 싱글스레드는 문맥 전환(Context Switching) 오버헤드가 없기 때문이다.
- 두 쓰레드가 서로 다른 자원을 사용할 경우 멀티스레드가 효율적이다.
- 동일한 자원에 대해 한 스레드가 작업하는 동안 다른 스레드는 대기 상태일 수 있다.
- 멀티코어일 경우, 한 스레드가 입력을 기다리는 동안 다른 스레드가 작업을 처리할 수 있어 효율적이다.
- 즉, 서로 다른 자원을 사용하는 경우, 스레드 간 자원 충돌이 없으므로 더욱 효율적.
◼️쓰레드 우선순위
쓰레드 우선순위를 지정할 수 있다. 우선순위 범위는 1~10이며 숫자가 높을수록 우선순위가 높다.
class ThreadEx8 {
public static void main(String args[]) {
ThreadEx8_1 th1 = new ThreadEx8_1();
ThreadEx8_2 th2 = new ThreadEx8_2();
th2.setPriority(7); //쓰레드 보통우선순위를 7로 변경
//따로 우선 순위를 지정하지 않을 경우 main의 기본 우선순위인 5을 할당
//setPriority() : 쓰레드 우선순위 지정
//getPriority() : 쓰레드 우선순위 반환
System.out.println("Priority of th1(-) : " + th1.getPriority() ); // 5
System.out.println("Priority of th2(|) : " + th2.getPriority() ); //7
//또한, Thread를 실행하기 전에만 우선순위를 정할 수 있다.
th1.start();
th2.start();
}
}
class ThreadEx8_1 extends Thread {
public void run() {
for(int i=0; i < 300; i++) {
System.out.print("-");
for(int x=0; x < 10000000; x++);
}
}
}
class ThreadEx8_2 extends Thread {
public void run() {
for(int i=0; i < 300; i++) {
System.out.print("|");
for(int x=0; x < 10000000; x++);
}
}
}
싱글코어의 경우, 우선순위가 7인 th2가 th1보다 높으므로 th2를 우선적으로 해결한 후 th1 수행한다.|||~을 거의모두수행하고 ---가 실행됨을 예상 가능하다.
멀티코어의 경우, 우선순위가 뭐가 됐건, 우선순위에 따른 차이가 거의 없다. (각 스레드가 별도의 코어에서 동시에 실행되기 때문에, 우선순위가 실행 시간에 큰 영향을 미치지 않는다.)
'Java' 카테고리의 다른 글
[Java] 김영한의 실전 자바 - 고급 1편 섹션6 동기화 - synchronized (0) | 2024.08.19 |
---|---|
[Java] 김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성 섹션2,3 스레드 제어와 생명주기 (0) | 2024.07.28 |
[Java] 김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성 섹션1 프로세스와 스레드 소개 (0) | 2024.07.16 |
[Java] 김영한의 실전 자바 - 중급편2 섹션10 컬렉션 프레임워크 - 순회, 정렬, 전체 정리 (0) | 2024.07.08 |
[Java] 김영한의 실전 자바 - 중급편2 섹션1 제네릭 - Generic1,Generic2 (0) | 2024.06.07 |