ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바 -thread(2) [5~8]
    언어/JAVA 2023. 3. 20. 16:17

     

    1.쓰레드의 우선순위

     

    쓰레드는 우선순위(priority)라는 속성을 가지고 있다.  우선순위에 따라 쓰레드가 얻는 실행시간이 달라진다.

    우선순위가 높으면, 더 많은 작업시간을 할당할 수 있다.

     

    -void setPriority(int newPriority) -쓰레드의 우선순위를 지정한 값으로 변경 (기본값 5)

    -int getPriority() -스레드의 우선순위를 반환한다.

     

    *JVM은 우선순위를 1~10까지 두고있고, winOS는 32단계의 우선순위를 가지고 있다. 쓰레드는 결론적으로 os의 스케쥴러에 의해 영향을 받으므로, 우리가 jvm을 통해 설정하는 우선순위는 희망사항일 뿐 강제될 순 없다.

     

    public class ThreadEX1 {
        //static long startTime =0;
        public static void main(String[] args) {
            Threadex th = new Threadex();
            Threadex2 th2 = new Threadex2();
            th.setPriority(7);
            th.start();
            th2.start();
        }
    }
    class Threadex extends Thread{
    
        @Override
        public void run(){
            for(int i=0; i<300;i++){
               System.out.printf("%s",new String("a"));
               for(int x=0; x<1000000;x++);
            }
        }
    }
    class Threadex2 extends Thread{
    
        @Override
        public void run(){
            for(int i=0; i<300;i++){
                System.out.printf("%s",new String("b"));
                for(int x=0; x<1000000;x++);
            }
        }
    }

    우선순위를 높여서 a,b를 출력한다. 매번 그런것은 아니지만, b가 많은 작업시간을 먼저 할당받을 때가 있다.

     

    2.쓰레드 그룹

     

    쓰레드 그룹이란 서로 관련된 쓰레드를 그룹으로 다루기 위한 것이다.

     

    -마치 폴더를 생성해서 파일을 관리하듯 쓰레드 또한 그룹을 생성해서 묶어서 관리할 수 있다.

    -쓰레드 그룹에 또다른 하위 쓰레드 그룹을 포함 시킬 수 있다. 

    -모든 쓰레드는 반드시 하나의 그룹에 속해야한다. 

    -Thread(ThreadGroup group, String name) Thread생성자에서 그룹 미지정시 main 쓰레드 그룹이 default로 설정된다.

    (쓰레드 그룹에 쓰레드를 포함시키려면 Thread생성자 이용해야함)

    -자신을 생성한 부모쓰레드 그룹과 우선순위를 상속받는다 (ex main에서 start()된 쓰레드는 main쓰레드 그룹,우선순위 5)

     

    *쓰레드는 기본적으로 묶여서 다뤄진다는 점과 쓰레드를 관리할 때 그룹으로 관리할 수 있다는 점을 기억해두자

     

    쓰레드 그룹과 관련된 메서드

    + ThreadGroup getThreadGroup() -자신이 속한 쓰레드 그룹 반환

       void uncaughtException(Thread t, Throwable e) 

     

     

    자바 어플리케이션이 실행되면, jvm은 main과 system이라는 쓰레드 그룹을 만든다

     jvm 운영에 필요한 쓰레드들을 생성해서 이 쓰레드 그룹에 포함시킨다.

     

    -main메서드를 수행하는 main이라는 이름의 쓰레드는 main쓰레드 그룹, 사비지컬렉션을 수행하는 finalizer쓰레드는 system쓰레드 그룹에 속한다. 

    -우리가 생성하는 모든 쓰레드 그룹은 main 쓰레드 그룹의 하위 쓰레드 그룹이 된다.(미지정시 그냥 main쓰레드 그룹에 포함)

     

     

    public class ThreadEX1 {
        //static long startTime =0;
        public static void main(String[] args) {
            ThreadGroup main = Thread.currentThread().getThreadGroup();
            ThreadGroup grp1 = new ThreadGroup("group1"); //쓰레드 그룹생성
            ThreadGroup grp2 = new ThreadGroup("group2"); //폴더만 생성한 격 아직 파일은 없다.
    
            ThreadGroup subGrp1 = new ThreadGroup(grp1,"sub1"); //group1의 하위 그룹 생성
    
            grp1.setMaxPriority(3); //group1의 모든 우선순위 3
    
            Runnable r = new Runnable(){ //쓰레드 만들려고 Runnable하나 지정
                @Override
                public void run() {
                    try{
                        Thread.sleep(1000);
                    }catch (InterruptedException e){}
                }
            };
    
            new Thread(grp1,r,"th1").start(); //각 그룹에 쓰레드 추가 후 실행
            new Thread(subGrp1,r,"th2").start(); //(그룹,"쓰레드 이름(변수명 말고 그룹내 식별)")
            new Thread(grp2,r,"th3").start();  //(그룹,runable r, "쓰레드이름")
    
            System.out.println(">>List of ThreadGrop: " +main.getName()+",Active Group "+main.activeGroupCount()+", Active Thread "
            +main.activeCount());
    
            main.list();
        }
    }

     

    3 데몬 쓰레드(daemon thread)

     

    데몬 쓰레드는 다른 일반 쓰레드의 작업을 돕는 보조적인 역할을 수행하는 쓰레드이다.

     

    -일반쓰레드가 모두 종료되면 데몬 쓰레드는 자동 종료된다.

    - 가비지컬렉터, 자동저장기능, 화면자동갱신기능 등이 데몬쓰레드의 예이다.

     

    데몬쓰레드 생성

     

    -무한루프와 조건문을 활용하여 run()을 채운다. ->계속 실행 대기상태, 특정조건이 만족되면 작업을 수행하고 다시 대기

    -void setDaemon(boolean on)을 이용해서 쓰레드를 데몬쓰레드 혹은 일반쓰레드로 변경한다. setDaemon은 반드시 start()전에 호출 되어야 한다.

     

    *boolean isDaemon() 쓰레드가 데몬인지 아닌지 확인 

     

    public class ThreadEX1 implements Runnable {
        static boolean autosave = false;
        public static void main(String[] args) {
            Thread t = new Thread(new ThreadEX1());
            t.setDaemon(true);
            t.start();
    
            for(int i=1; i<=10 ; i++){
                try{
                    Thread.sleep(1000);
                }catch (InterruptedException e){}
                System.out.println(i);
                if(i==5)autosave=true;
            }
            System.out.print("프로그램을 종료합니다.");
            };
    
        @Override
        public void run() {
            while(true){
                try{
                    Thread.sleep(3*1000);
                }catch (InterruptedException e){}
                if(autosave){
                    autosave();
                }
                }
            }
        public void autosave() {
            System.out.println("작업파일이 자동저장됨");
        }
    }
    public class ThreadEX1  {
    
        public static void main(String[] args) throws Exception{
            ThreadEx2 t1 = new ThreadEx2("Thread1");
            ThreadEx3 t2 = new ThreadEx3("Thread2");
            t1.start();
            t2.start();
    
            }
    }
    
    class ThreadEx2 extends Thread{
        ThreadEx2(String name){
            super(name);
        }
        public void run(){
            try{
                sleep(5*1000);
            }catch (InterruptedException e){}
        }
    }
    class ThreadEx3 extends Thread{
        ThreadEx3(String name){
            super(name);
        }
    
        public void run(){
            Map map  = getAllStackTraces();
            Iterator it = map.keySet().iterator();
            int x=0;
            while(it.hasNext()){
                Object obj = it.next();
                Thread t = (Thread)obj;
                StackTraceElement[] ste = (StackTraceElement[]) (map.get(obj));
                System.out.println("["+ ++x+"] name :"+t.getName()+", group :"+t.getThreadGroup().getName() +",daemon: "+t.isDaemon());
                //쓰레드 관련내용 출력 
                
                for(int i=0; i<ste.length;i++)
                    System.out.println(ste[i]); //element관련내용출력 
                System.out.println();
            }
    
        }
    }
    
    //getAllStackTraces() 실행중, 대기상태 , 작업완료x 모든 쓰레드 kv
    key thread val StackTraceElement[]

     

    4 쓰레드의 실행제어

    쓰레드 프로그래밍이 어려운 이유는 동기화와 스케줄링 때문이다.

    쓰레드 스케줄링을 잘하려면 쓰레드 상태와 관련된 메서드를 잘 알아야 한다.

     

    4.1 쓰레드 스케쥴링 메서드

    출처:https://math-coding.tistory.com/173

          각 메서드들은 추후에 자세히 알아볼 것이다.

     

    4.2 쓰레드의 상태 

     

    출처:https://velog.io/@bae_mung

     

    쓰레드의 상태는  다음과 같이 나눌 수 있다.

     

    생성

    NEW - 쓰레드가 생성되고 아직 start()가 호출되지 않은 상태 

     

    실행대기

    RUNNABLE - 실행 중 혹은 실행 가능 상태 -start() ,yield() 쓰레드 순서양보

     

    --일시정지--------------------------------

    BLOCKED - 동기화블럭에 의해서 일시정지 상태(LOCK가 풀릴 때까지 기다리는중) 

     

    WAITING, TIMED-WAITING - 쓰레드 작업이 종료된 것은 아니지만, 실행가능하지 않은 일시정지 상태. TIMED-WAITING은 일시정지 시간이 지정된 경우이다.

     

    (suspend <-> resume(), nofity()<->wait(), interrupt()<->sleep() + time-out, i/o block, join())

    -----------------------------------------------

    소멸

    TERMINATED - 쓰레드 작업이 종료된 상태이다. 

     

     

    참고자료:

    자바의정석 (남궁성 저)

    '언어 > JAVA' 카테고리의 다른 글

    자바 - Arrays 클래스와 Comparator  (0) 2023.03.23
    자바 - Thread(4) 동기화  (0) 2023.03.21
    자바 - thread(3) 실행제어 메서드 예제  (0) 2023.03.21
    자바 - thread(1) 기본특성 (1~4)  (0) 2023.03.20
    자바 - Generics  (0) 2023.03.16
Designed by Tistory.