18일차 - Java강의(쓰레드 명령어)

2024. 8. 7. 21:38·Java & Spring/Java
목차
  1. ◇ 쓰레드 상태
  2. ◇ 쓰레드 제어

◇ 쓰레드 상태

  • 쓰레드 상태 : 실행과 대기를 반복하며 run()메서드를 수행, 메서드가 종료되면 실행을 멈춤


  • 일시정지 : 일시정지는 쓰레드가 실행 할 수 없는 상태, 다시 실행하기 위해서는 다시 실행대기로 넘어가야함
  • 쓰레드 상태 정리
    상태 Enum 설명
    객체생성 NEW 쓰레드 객체 생성, start()메서드 호출 전
    실행대기 RUNNABLE 실행 상태로 언제든지 갈 수 있는 상태
    일시정지 WAITING 다른 쓰레드가 notify할 때까지 기다리는 상태
    일시정지 TIMED_WATING 주어진 시간동안 기다리는 상태
    일시정지 BLOCKED 사용하고자 하는 객체의 Lock이 풀릴 때까지 기다리는 상태
    종료 TERMINATED 쓰레드 작업이 종료된 상태

◇ 쓰레드 제어

 

 

  • sleep() : 현재 쓰레드를 지정된 시간동안 멈추게 한다.
    ※sleep()는 쓰레드 자기 자신에 대해서만 멈출 수 있다.
    try {
        Thread.sleep(2000); // 2초
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    - 사용방법
    → Thread.slee(ms) 밀리초 단위로 설정
    → 예외처리를 해야함, sleep상태에서 interrupt()를 만나면 다시 실행되어 InterruptedException이 발생할 수 있기떄문→ 특정 쓰레드를 지목해서 멈추게 하는 것은 불가능(static메서드이기때문)

  • interrupt() : 일시정지 상태인 쓰레드를 실행대기 상태로 만듭니다.
    public class Main {
        public static void main(String[] args) {
            Runnable task = () -> {
                try {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("task : " + Thread.currentThread().getName());
            };
    
            Thread thread = new Thread(task, "Thread");
            thread.start();
    
            thread.interrupt();
    
            System.out.println("thread.isInterrupted() = " + thread.isInterrupted());
    
        }
    }
    - 위 코드에서 thread.interrupt();가 실행되면 sleep을 깨워
       task에서 catch문으로 들어가 sleep아래 코드가 실행되지않는다.
    위와 같이 while문을 통해 상태를 체크하면 오류를 방지할 수 있다.

  • Runnable task = () -> { while (!Thread.currentThread().isInterrupted()) { try { Thread.sleep(1000); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e) { break; } } System.out.println("task : " + Thread.currentThread().getName()); };
  • join() : 정해진 시간동안 지정한 쓰레드가 작업하는 것을 기다린다.
    ※ 시간을 지정하지 않았을 때는 지정한 쓰레드의 작업이 끝날 때까지 기다린다.
    Thread thread = new Thread(task, "thread");
    
    thread.start();
    
    try {
        thread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }


  • yield() : 남은 시간을 다음 쓰레드에게 양보하고 자신은 실행 대기 상태가 된다.
    public class Main {
        public static void main(String[] args) {
            Runnable task = () -> {
                try {
                    for (int i = 0; i < 10; i++) {
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName());
                    }
                } catch (InterruptedException e) {
                    Thread.yield();
                }
            };
    
            Thread thread1 = new Thread(task, "thread1");
            Thread thread2 = new Thread(task, "thread2");
    
            thread1.start();
            thread2.start();
    
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            thread1.interrupt();
    
        }
    }
    - 실행되면 task에 의해 각 쓰레드가 자신의 이름과 함께 찍히게 된다.
    - sleep(5000)에 의해 5초 후 thread1.interrupt()가 실행된다.
    - catch문에 의해 thread1은 yield()가 실행되고 남은 시간동안 thread2만 동작하게된다.
  • synchronized : 한 쓰레드가 진행중인 작업을 다른 쓰레드가 침범하지 못하도록 막는 것
                            (임계영역을 설정하여 Lock을 가진 하나의 쓰레드만 출입이 가능)
    ※ 멀티 쓰레드의 경우 여러 쓰레드가 한 프로세스의 자원을 공유해서 작업하기 때문에 서로에게 영향을 줄 수 있다.
    - 메서드 전체를 임계영역으로 지정
    public synchronized void asyncSum() {
    	  ...침범을 막아야하는 코드...
    }
    - 특정 영역을 임계영역으로 지정
    synchronized(해당 객체의 참조변수) {
    		...침범을 막아야하는 코드...
    }


    - 예제
    public class Main {
        public static void main(String[] args) {
            AppleStore appleStore = new AppleStore();
    
            Runnable task = () -> {
                while (appleStore.getStoredApple() > 0) {
                    appleStore.eatApple();
                    System.out.println("남은 사과의 수 = " + appleStore.getStoredApple());
                }
    
            };
    
            for (int i = 0; i < 3; i++) {
                new Thread(task).start();
            }
        }
    }
    
    class AppleStore {
        private int storedApple = 10;
    
        public int getStoredApple() {
            return storedApple;
        }
    
        public void eatApple() {
            if (storedApple > 0) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                storedApple -= 1;
            }
        }
    }

    다음 예제를 실행하게되면
    - for문을 통해 3개의 쓰레드가 동시에 NEW하게되고 start()하게된다.
    - 각 쓰레드들은 eatApple을 수행하게되는데 만약 남은 사과가[9, 8, 7], [6, 5, 4], [3, 2, 1] 이렇게 줄어들다가
    - 1이 남은상황에서 task의 while문에 진입하게 되면 각 쓰레드들이 진입 당시에는 1개가 남아있는 상황이다.
    - eatApple의 if문에서도 아직 사과는 1개가 남아있기 떄문에 try문으로 진입하게되고
    - 마지막 실행이 되면 남은 사과 출력은[0, -1, -2]와 같은 상황이 발생하게된다.

    eatApple()메서드를 다음과 같이 synchornized 하게 되면 해결 할 수 있다.
      public void eatApple() {
            synchronized (this) {if문}
  • wait() : synchornized()를 수행하다가 작업을 더이상 진행할 상황이 아니면 쓰레드가 Lock을 반납하고 기다리게 함

  • notify() : 추후에 작업을 진행할 수 있는 상황이 되면 notify()호출

  • Lock
    1. ReentrantLock : 재진입 가능한 일반적인 베타 Lock,
                                특정 조건에서 Lock을 풀고, 나중에 다시 Lock를 얻어 임계 영역으로 진입이 가능
    2. ReentrantReadWriteLock : 읽기, 쓰기 Lock을 따로 제공
                                                 읽기에는 공유적이고, 쓰기에는 베타적인 Lock
                                                 읽기 Lock이 걸려있으면 다른 쓰레드들도 읽기 Lock을 중복으로 걸고 읽기 수행가능
                                                 읽기 Lock이 걸려있는 상태에서 쓰기 Lock을 거는것은 불가(데이터 변경 방지)
    3. StampedLock : 데이터를 변경하기전에 Lock를 걸지않는 것
  • Condition : 특정 조건이 맞는 쓰레드를 깨우는 기능(notify()는 쓰레드 구분을 할 수 없다)
    1. await() : 특정 지점에 wati()
    2. signal() : 특정 지점에 notify()

 

 

 

 

 

 

'Java & Spring > Java' 카테고리의 다른 글

HTTP 요청과 응답에 사용되는 클래스들  (0) 2025.02.06
csv파일으로 더미데이터 생성하기  (0) 2024.11.08
14일차 - Java강의(쓰레드)  (0) 2024.08.01
13일차 - Java강의(예외, 제네릭)  (0) 2024.07.31
11일차 - Java강의(계산기 실습, 클래스화, 추상화)  (0) 2024.07.29
  1. ◇ 쓰레드 상태
  2. ◇ 쓰레드 제어
'Java & Spring/Java' 카테고리의 다른 글
  • HTTP 요청과 응답에 사용되는 클래스들
  • csv파일으로 더미데이터 생성하기
  • 14일차 - Java강의(쓰레드)
  • 13일차 - Java강의(예외, 제네릭)
DJ.Kang
DJ.Kang
백엔드 개발 기록 블로그
  • DJ.Kang
    DJ Hello World
    DJ.Kang
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 이론공부
      • 시스템설계
      • Java & Spring
        • TIL
        • 트러블슈팅
        • 고도화
        • 알고리즘
        • 코딩테스트
        • Java
        • Spring
        • Thymeleaf
      • 프로젝트
        • coin-trading
        • 트러블슈팅
      • Docker
      • DB
      • AWS
      • CI-CD
      • 웹
      • git & github
      • 구인공고분석
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    java arrays.copyofrnage()
    Java this
    java 에라토스테네스의 체
    개발로드맵
    java 제어자
    프로그래머스 java 기초트레이닝
    java two-pointer
    java기초
    데이터 타입
    java super
    java
    데이터 크기
    자료구조
    java enhance switch
    java 멤버
    프로그래머스 java 기초 트레이닝
    java 유클리드 호제법
    java 세수의합
    Java 생성자
    java 메서드
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
DJ.Kang
18일차 - Java강의(쓰레드 명령어)
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.