ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 쓰레드 기본
    언어/JAVA 2023. 8. 25. 12:51

    1. 멀티스레드의 개념

     

    - 프로세스: 운영체제에서 실행중인 프로그램

    - 멀티 태스킹: 두 가지 이상의 작업을 동시에 처리하는 것 (멀티프로세스,멀티스레드)

    - 스레드: 코드의 실행 흐름, 하나의 프로세스에서 멀티 태스킹

     

    > 멀티 프로세스 환경에서 하나의 프로세스의 오류가 다른 프로세스에 영향x

    > 멀티 스레드는 하나의 스레드 예외는 다른 스레드에 영향 

     

    1.2 main 스레드 

     

    - 자바 프로그램은 메인 스레드가 main()메서드의 시작과 함께 실행된다.

    - 하나의 스레드는 첫 코드부터 순차적으로 실행, 마지막 코드 실행 혹은 return문을 만나면 종료 

    - 메인 스레드에서 추가 작업 스레드를 만들어서 실행 가능 

    - 멀티 스레드에서는 작업 중인 스레드가 남아있으면, 프로세스 종료하지 않는다. 

     

    2. 작업 스레드의 생성 

     

    - 멀티 스레드 프로그램은 몇 개의 작업을 병렬로 실행할지 결정하고, 작업별 스레드를 생성해야함 

     

    2.1 Thread클래스 생성 

     

    Thread thread = new Thread(Runnable r);
    //> Runnable 인터페이스 구현체를 매개변수로 생성 
    //> 함수형 인터페이스임 람다식 가능 (매개변수x return x)
    //> 익명 클래스 가능 
    
    thread.start //()호출 
    
    
    Thread thread = new Thread(){
    	@Override
    	//..
    }
    Thread thread = new Thread(()->{
    	..//
    })
    
    public class MyThread extends Thread{
    	@Override 
        public void run(){
        //..
       
        }
    
    }

    - 스레드 이름 설정 

    thread.setName("") //스레드 이름설정
    Thread.currentThread().getName() // 실행중인 스레드 이름
    //getName()인 Thread의 인스턴스변수

     

    3. 스레드 상태 (실행제어)

     

    출처: https://widevery.tistory.com/28

     

    - 스레드 객체를 생성하고 start메서드를 실행하면, 스레드는 실행 대기 상태가 된다. 

    - 실행 대기하는 스레드는 CPU의 스케쥴링에 따라 CPU를 점유하고 run()메서드를 실행한다.(실행상태)

    -  모든 스레드는 실행 대기와 실행 상태를 번갈아가며 자신의 run()을 완료한다.

    - run()이 종료되면, 스레드는 종료상태가 된다.

     

    > 실행 -> 일시정지 상태로 갈 수 있는데, 이는 스레드를 실행할 수 없는 상태이다. 다시 실행하기 위해서는 일시정지에서 실행대기로 가야함 

     

    3.1 스레드 실행 제어 메서드 

     

    - 일시 정지로 보냄 

    sleep(long mills)  주어진 시간동안 스레드 일시 정지 상태로 만든다 -> 시간이 지나면 자동 실행대기 
      static메서드

    join() join()호출한 스레드는 일시정지 -> join()메서드 가진 스레드 종료시 실행대기
    *다른스레드객체.join() 
    wait() 동기화 블럭 내에서 스레드 일시정지 (Object 메서드)

    - 일시 정지에서 벗어남

    interrupt()  일시정지 상태일 경우, InterruptedException을 발생시켜 실행 대기 혹인 종료로 만듦
      *다른스레드가 일시정지상태인 스레드를 깨워주는 것
    notify()
    notifyAll()
    wait()메서드로 인해 일시정지된 스레드 실행대기 (Object 메서드)

    - 양보

    yield() - 실행 상태에서 다른 스레드에게 실행 양보하고 실행 대기가 된다. (static)

     

     public static void main(String[] args) {
            ThA tha = new ThA();
            tha.start();
            tha.setThre(Thread.currentThread());
            try {
                tha.join();
            } catch (InterruptedException e) {
               
            }
            System.out.println("tha.getSum() = " + tha.getSum());
        }
        
        //join(); -> tha내부에서 main스레드의 일시정지 풀도록 interrupt()발생시키면 풀림
        
        public void run(){
                while(true){
                    if(work)System.out.println(getName() +" 작업처리중");
                    else {
                        System.out.println(getName()+"양보");
                        Thread.yield();
                    }
                }
            }
      //양보 (static 메서드들은 currentThread에 적용)

     

    3.2 스레드 동기화를 이용한 실행제어

     

     - 멀티스레드는 하나의 객체를 공유할 수 있다. 

     - 다른 스레드에 의해 객체 내부 데이터가 쉽게 변경될 수 있기 때문에 의도하지않은 결과 불러올 수 있다.

     - 한 스레드 작업이 끝날 때 까지 객체에 잠금을 걸 수 있다. > 동시화 메스드와 블록 

     - 객체 내부에 동기화 메서드와 블럭이 여러개가 있다면, 스레드가 이들 중 하나 실행시 

        다른 동기화 메서드 및 블럭 실행 불가하다.

     

    > synchronized 키워드 -> 동기화 메서드 및 블럭 생성 

     

    public synchronized void met(){
    
    }
    
    public void method(){
    
    	sychronized(공유객체){
        	//동기화 블럭
            // 단 하나의 스레드만 실행가능
        }
        //여러스레드에서 실행가능
    }
      public synchronized void setMemory(int memory){
            this.memory= memory;
            try{
                Thread.sleep(5000);
            }catch (InterruptedException e){
    
            }
            System.out.println(Thread.currentThread().getName() + " : "+getMemory());
    
        }
    
        public void setMemory2(int memory){
            System.out.println(Thread.currentThread().getName() +" hi");
            System.out.println("동기화블럭 시작할게");
            synchronized (this){
                this.memory=memory;
                try {
                    System.out.println(Thread.currentThread().getName()+"잠");
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
    
                }
                System.out.println(Thread.currentThread().getName() + " : "+getMemory());
            }
        }
        
        //Th1
        
         @Override
            public void run() {
                calcul.setMemory(100);
                try {
                    sleep(2000);
                } catch (InterruptedException e) {
                }
                calcul.prit();
            }
            
       //Th2
       
          @Override
            public void run() {
                calcul.setMemory2(50);
            }

    - 먼저 Th1이 run()실행하는 순간 동기화 method실행 -> sleep

       ->이 타이밍에 Th2가 동기화 안된 부분 출력 -> 동기화 블럭에서 기다림 

    - Th1이 작업완료 후 sleep -> th2 동기화된 객체에 접근해서 남은 작업 실행 (객체 동기화)

    - Th1이 동기화되지않은 메서드 접근 (ok) -> Th2나머지 작업 완료 후 출력

     

    3.3 wait()과 notify()이용한 스레드 실행제어(동기화 관련)

     

     - 경우의 따라 두 개의 스레드를 교대로 번갈아 가며 실행할 때도 있다. 

     - 정확한 교대작업이 필요할 시에 자신의 작업이 끝나면 상대방 스레드를 일시 정지 상태에서 풀어주고 자신을 일시 정지로 만들면 된다.

     - 이 방법의 핵심은 공유객체에 있다. 

     - 공유객체가 두 스레드가 작업할 내용을 동기화 메서드로 가지고 있다가 한 스레드 작업이 완료되면, notify메서드를 호출

       자신은 두번 작업하지 않도록 wait()한다.

     

    - notify()는 일시정지 중 한개의 스레드 All()은 모든 스레드 깨운다. -> 핵심은 동기화 블럭 내에서만 사용가능 

     

     public synchronized void methodA(){
            Thread thread =Thread.currentThread();
            System.out.println(thread.getName() + "methodA 실행");
            notify();
            try{
                wait();
            }catch (InterruptedException e){}
        }
        
        //동기화 메서드를 점유하던 스레드가 일시정지 상태 깨우고, 자신은 wait()상태
        // 아직 동기화 메서드가 종료된 것 아니지만 다른 스레드가 객체 동기화 블럭 및 메서드에 접근가능

     

    4. 스레드 안전종료 

     

    - run() 중간에 작업을 즉시 중단하고 싶을 때

    - 주로 조건을 이용하는 방법과 interrupt()메소드를 사용한다.

     

    4.1 조건이용

     

    public void run(){
    	while(!stop){ //특정 조건에서 스레드 종료시킴 
        
        	//스레드가 반복 실행하는 코드
        }
    		//스레드 사용리소스 정리 
    
    }//스레드 종료

    4.2 interrupt()이용

    Thread tha = new Thread();
    tha.start();
    tha.interrupt();
    
    //tha의 run()
    public void run(){
    	try{
        	while(true){
            
            //...
            Thread.sleep(1); // 일시정지
            }
        
        }catch(InterruptedException e){
        	//리소스 정리
        }
    
    }

    * 스레드가 실행대기 혹은 실행중일 때는 interrup()가 작동하지 않는다 따라서 다음과 같은 메서드 활용하자 

    Thread.interrupted() // 정적메소드 현재 스레드에 작용
    objThread.isInterrupted() // 인스턴스 메소드 (특정스레드)

     

    5. 데몬스레드 

     

     - 스레드 작업을 돕는 보조적인 역할의 스레드이다. (주 스레드 종료스 데몬 스레드 종료된다)

     - 워드프로세서 자동저장, 미디어 플레이어 동영상 및 음악 재생 등등 

     - 데몬스레드를 만들기 위해서는 주 스레드가 데몬이 될 스레드의 setDemon(true)를 호출하면 된다.

     public static void main(String[] args) {
            AutosaveThread autosaveThread =new AutosaveThread();
            autosaveThread.setDaemon(true);
            autosaveThread.start();
    
            try{
                Thread.sleep(3000);
            }catch (InterruptedException e){}
    
            System.out.println("메인 스레드 종료");
        }
        
        
        //demon
         @Override
        public void run() {
            while (true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    break;
                }
                save();
            }
        }

     

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

    자바스터디(1)  (0) 2023.10.18
    자바 네트워크 네트워크 입출력 (1) - TCP  (0) 2023.08.22
    Java - 일급컬렉션  (0) 2023.07.25
    Servlet-JSP MVC07 파일 수정하기  (0) 2023.07.24
    Java - File클래스  (0) 2023.07.24
Designed by Tistory.