본문 바로가기

프로그래밍/JAVA

[JAVA} 쓰레드(Thread) 2편


JAVA의 정석(2nd Edition) (남궁 성 著) 참조해 내용을 작성했으며

개인적인 공부 내용을 적은 것이므로 오류가 있을 수 있습니다.


1편 http://whatisthenext.tistory.com/77



5. 쓰레드의 우선순위


<사용자에게 빠르게 반응해야 작업의 우선순위가 더 높아야 한다>


쓰레드의 우선순위는 메서드와 필드로 정해줄 수 있다.


void setPriority(int newPriority) : 쓰레드의 우선순위를 지정한 값으로 변경하는 메서드

int getPriority() : 쓰레드의 우선순위를 반환한다


public static final int MAX_PRIORITY = 10    // 최대

public static final int MIN_PRIORITY = 1      // 최소

public static final int NORM_PRIORITY = 5   // 보통


1. 우선순위는 상대적이어서 1과 2로 설정한 것과 ↔  9와 10으로 설정한 것이 똑같다.

2. 우선순위는 쓰레드를 생성한 쓰레드로부터 상속받는다. 

    EX) main 메서드는 우선순위가 5이다. 따라서 메인메서드에서 생성하는 쓰레드의 우선순위는 5가 된다.


public class MyThread {
public static void main(String[] args) throws Exception {

MultiThread1 multi1 = new MultiThread1();
MultiThread2 multi2 = new MultiThread2();

multi1.setPriority(5);
multi2.setPriority(8);

System.out.println("multi1의 우선순위 : " + multi1.getPriority());
System.out.println("multi2의 우선순위 : " + multi2.getPriority());

multi1.start();
multi2.start();
}
}
class MultiThread1 extends Thread{
public void run(){
for(int i=0; i<300; i++){
System.out.print("-");
for(int x=0; x<1000000; x++);
}
}
}
class MultiThread2 extends Thread{
public void run(){
for(int i=0; i<300; i++){
System.out.print("☆");
for(int x=0; x<1000000; x++);
}
}
}


1번 쓰레드는 우선순위 5(기본값), 2번 쓰레드는 우선순위 8을 주었다.

우선순위가 높은 것이 처음에 더 많이 출력될 것이다.

<처음에는 ☆(우선순위 8)이 많이 출력되는 것을 볼 수 있다>

※ 우선순위가 너무 높으면 한 번에 작업이 끝날 수 있기 때문에 for문을 통해 작업을 지연시켰다.


6. 쓰레드 그룹(thread group)


음악에는 힙합 장르도 있고, R&B 장르도 있고, 발라드 장르도 있고, 클래식 장르도 있다.

이처럼 서로 관련된 쓰레드를 그룹으로 묶은 것이 쓰레드 그룹(thread group)이다.


7. 데몬 쓰레드(daemon thread)


데몬(Daemon)이란 리눅스, 유닉스 계열의 운영체제에서 백그라운드로 동작하는 프로그램을 말한다.

윈도우는 보통 서비스(service)라고 얘기하는데, 자바에도 데몬 쓰레드라고 해서 이와 유사하게 동작하는 쓰레드를 만들 수 있다.


즉, 백그라운드의 특별한 작업을 처리하는 용도로 쓰인다. 예를 들어서 가비지 컬렉터, 워드프로세서의 자동 저장기능, 맞춤법 검사, 화면자동갱신 등이 있다. 


<데몬쓰레드는 메인쓰레드가 종료되면 강제적으로 종료된다>


public class MyThread implements Runnable {
@Override
public void run(){
while(true){
System.out.println("데몬 쓰레드 실행 ");

try{
Thread.sleep(500); // 무한루프에서 0.5초씩 쉬면서 프린트문 출력
} catch (InterruptedException e){
e.printStackTrace();
break;
}
}
}


public static void main(String[] args){
Thread th = new Thread(new MyThread());
th.setDaemon(true); // true를 주면 데몬 쓰레드로 설정이 된다.
th.start();

try{
Thread.sleep(1000); // 1초 후에 종료
} catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("메인 쓰레드 종료");
}
}

<데몬 쓰레드는 일반 쓰레드의 작성방법과 동일하며, 실행 전에 setDaemon(true)만 호출하면 된다>


8. 쓰레드의 실행제어


<join>

public class MyThread{

static long startTime = 0;

public static void main(String args[]){

A th1 = new A();
B th2 = new B();

th1.start();
th2.start();
startTime = System.currentTimeMillis();

try{
th1.join();
th2.join();
} catch (InterruptedException e){ }
System.out.print("소요시간 : " +                       ((float)(System.currentTimeMillis() - MyThread.startTime))/1000 + "초");
}
}

class A extends Thread{
public void run(){
for(int i=0; i<300; i++){
System.out.print("-");
}
}
}

class B extends Thread{
public void run(){
for(int i=0; i<300; i++){
System.out.print("|");
}
}
}


<join을 사용하지 않으면 메인메서드가 중간에서 끝나버린다>

<join을 사용하면 다른 쓰레드가 끝날 때까지 메인메서드를 기다리게 한다>

<메인쓰레드를 '지정시간'만큼 대기하려면 join(long millis) 또는 join(long millis, int nanos를 사용한다.>

∴ join 메서드는 한 쓰레드의 작업 중간에 다른 쓰레드의 작업이 필요할 때 사용한다.


<순차적으로 쓰레드를 실행하고 싶다면 오른쪽 처럼 코드를 변경하면 된다>



<sleep(), suspend(), resume(), stop()> 

public class MyThread{

public static void main(String args[]){

A r = new A();
Thread th1 = new Thread(r, "*");
Thread th2 = new Thread(r, "**");
Thread th3 = new Thread(r, "***");

th1.start();
th2.start();
th3.start();

try{
Thread.sleep(2000); // 2초 동안 쓰레드를 멈춤
th1.suspend(); // suspend() 호출되면 쓰레드는 일시정지 상태가 된다.
Thread.sleep(2000);
th2.suspend();
Thread.sleep(3000);
th1.resume(); // resume() 호출되면 쓰레드는 다시 실행대기상태가 된다.
Thread.sleep(3000);
th1.stop(); // stop() 호출하면 쓰레드는 즉시 종료된다.
th2.stop();        
Thread.sleep(2000);
th3.stop();
} catch (InterruptedException e){}
}
}

class A implements Runnable{
public void run(){
while(true){
System.out.println(Thread.currentThread().getName());
try{
Thread.sleep(1000);
} catch (InterruptedException e){}
}
}
}


try문 끝을 보면 th1 과 th2는 stop() 메서드에 의해 먼저 종료된다.

따라서 마지막 작업은 th3 ( "***" ) 로만 실행된다.


<뒤죽박죽 출력이 된다>

※ suspend(), resum(), stop()은 쓰레드를 교착상태로 만들기 때문에 deprecated (사용 자제)하는 것이 좋다.


<메서드들이 좀 더 잘 먹히게 수정했다

public class MyThread{

public static void main(String args[]){

A r1 = new A();
A r2 = new A();
A r3 = new A();

Thread th1 = new Thread(r1, "A");
Thread th2 = new Thread(r2, "BBB");
Thread th3 = new Thread(r3, "CCCCCC");

th1.start();
th2.start();
th3.start();

try{
Thread.sleep(2000); // 2초 동안 쓰레드를 멈춤
r1.suspend(); // suspend() 호출되면 쓰레드는 일시정지 상태가 된다.
Thread.sleep(2000);
r2.suspend();
Thread.sleep(3000);
r1.resume(); // resume() 호출되면 쓰레드는 다시 실행대기상태가 된다.
Thread.sleep(3000);
r1.stop(); // stop() 호출하면 쓰레드는 즉시 종료된다.
r2.stop();
Thread.sleep(2000);
r3.stop();
} catch (InterruptedException e){}
}
}

class A implements Runnable{

boolean suspended = false;
boolean stopped = false;

public void run(){

while(!stopped){
if(!suspended){
System.out.println(Thread.currentThread().getName());
try{
Thread.sleep(1000);
} catch(InterruptedException e){}
}
}
System.out.println(Thread.currentThread().getName() + " - stopped");
}

public void suspend(){
suspended = true;
}

public void resume(){
suspended = false;
}

public void stop(){
stopped = true;
}
}


'프로그래밍 > JAVA' 카테고리의 다른 글

캡슐화  (0) 2017.01.31
생성자를 포함하는 클래스의 정의  (0) 2017.01.29
[JAVA] 쓰레드(Thread) 1편  (0) 2016.11.02
[JAVA TIP] 글자크기 바꾸기, 음영처리 바꾸기  (0) 2016.11.01
[JAVA] 제너릭(Generic)  (0) 2016.10.25