스레드

6.새로운 스레드로 print 메소드 호출하기

개별적으로 동시에 호출되도록 하고 싶다.
main흐름말고 다른 문맥 이것이 스레드이다.
이 함수이름이 run()이고 이게 정의되어있는게 runnalbe인터페이스이다.
start()를 해줘야 시작할 수 있다.

Thread thread1 = new Thread(Runnable(익명객체));
Main에서 사용하는게 아니라 별도의 시간을 분할해서 사용한다.

public static void main(String[] args) {
    Thread th1 = new Thread(new Runnable() {
        @Override
        public void run() {
            print1();
        }
    });

    Thread th2 = new Thread(new Runnable() {
        @Override
        public void run() {
            print2();
        }
    });

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

    for (int i = 0; i < 100; i++) {
        System.out.printf("main : %d\n", i + 1);
    }
}

각자 문맥을 가지고 순서없이 실행된다. main sub1 sub2 뒤죽박죽으로 실행됨

7. 스레드 식별속성

스레드를 식별하는 이유와 그것을 위한 속성
스레드가 가지고 있는 자식을 식별하는 속성이잇다.
왜 필요한가? 똑같은 로직잇는것을 함수 2개를 만들엇다. 이 같은 로직을 두개함수만든것도 비현실적이고 스레드 2개만든것도 비현실적이다.

1개의 로직만으로 여러스레드로 호출하면된다.
print가 여러번 실행하는데 스레드가 돌아가면서 출력한다. 그런데 1스레드 내용인지 2스레드 내용인지 알수없다.
이것을 알아보도록 식별하려고 한다. 누가 실행하고 있는지 알고싶다.
이것이 스레드를 식별하는 속성이다.
스레드를 식별하는 방법에는 ID 식별값, Name 이름, Priority 우선순위(클수록 높음), State 상태(new, runnalbe,,blokced, wating, time wating,terminated)가 있다.
같은 run을 사용하도록 할것이다.

Thread클래스의 정적메소드 currentThread()로 얻을 수 있다.
id는 자동으로 부여되고 이름은 마음대로 부여할 수 있다.

Thread th1 = new Thread(subMain);
th1.setName("sub1");
Thread th2 = new Thread(subMain);
th2.setName("sub2");

private static void print() {
    for (int i = 0; i < 100; i++) {

        Thread th = Thread.currentThread();
        System.out.printf("%s[%d] : %d\n", th.getName(), th.getId(), i + 1);
    }
}

스레드의 이름은 setName으로 줄 수 있다.
Thread th = Thread.currentThread();
이렇게 되면 식별자에 따라서 다른 행동이 되게 할 수도 있다.

8. TIMED_WAITING 스레드 상태 #1

스래드의 상태 Status를 알아보고자 한다. 영향을 주는 메소드를 알아보고자 한다.
이걸 사용햇을 경우
sleep
스레드는 여러개 만들수있는데 줄세워서 하나씩만 사용가능하다.
start()하면 바로 시작이 아니라 runnable상태가 되서 기다린다.
기다리다가 앞의 스레드가 시간을 다쓰면 running에 가서 실행된다.
실행중에 sleep을 호출하면 뒤로가는게 아니라 TIMED_WAITING이라는 버퍼에가서 기다린다.
본인차례라고 바로 running에 가는게아니라 runnable로 가서 준비하게 된다.

9. 보조스레드 종료문제와 waiting상태

timed waintg이아닌 그냥 waiting상태
보통 프로그램이 끝낫다하면 메인함수가 끝나는 것을 프로그램끝이라고 생각한다.
프로그램로직이 끝나도 안끝나는 경우가 있는데 다른스레드가 아직 실행중일때 이런게 발생한다.
메인스레드가 종료되엇는데 보조스레드가 할일이 남아있는다면 프로세스가 끝나지 않는다.

메인이끝낫는데 보조를 냅둘수는 없으니 보조가 끝나고 메인이 기다렷다가꺼지게하는게 좋다.
이럴때 사용하는 것이 join메소드이다. 메인스레드가 끝날때가지 waiting한다.
끝날때에도 메인이 끝낫다고 스레드가 끝나는게 아니라 다른 순서로 끝날 수도 있다.

if (th1.isAlive()) {
th1.join();
}
작업중인지 확인하고 작업중이라면 join하게 햇다.
join하게 되면 Main은 WAITING 상태가 된다.

10.스레드 종료방법 interrupt()

보조스레드 종료시키기
join의 문제점이 있다.
보조 스레드를 기다리는 것도 한계가 있다. 보조스레드가 영원히 안끝나면 프로그램이 끝나지를 않는다.
join에 매개변수를 넣을 수있다. 시간만큼 일하고 후에 끝낸다.

if (th1.isAlive()) {
    try {
        th1.join(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

th1.interrupt(); 방해를 주는것이다. 방해만 준다고 끝나는게 아니라 스레드가 인식하게 해야한다.
방해를 주면 멈추게 해줘야한다.

if(th.isInterrupted()) {
    System.out.println("------중지---");
    return;
}

확인하고 멈추게하기

그런데 자고있으면 조건검사를 할 수 없다. 엄청오래잔다면? 인식할 수없다.
sleep이던 join이던 wait가되면 깨게 하고싶다면?

try {
    th.sleep(20);
} catch (InterruptedException e) {
    //e.printStackTrace();
    System.out.println("누가나를 깨운거야");
    return;
}

wating된시점에 예외를 발생해서 멈추면된다.

11. 스레드 우선순위와 데몬스레드

특정 스레드에 우선순위를 줄수 있다. 범위 MIN(1) ~ MAX(10)으로 숫자클수록 우선순위가 높다.
th2.setPriority(Thread.MIN_PRIORITY); / th2.setPriority(Thread.MAX_PRIORITY);
하면 각각 가장나중 / 가장먼저로 우선순위로 줄수있다.

데몬스레드(유령스레드)는 무엇인가
th2.setDaemon(true); 하면 데몬스레드로 설정할 수 있다.
이 효과가 무엇인가? 흔히 스레드를 만들어서 시작하면 보조업무를 처리하는 것이다.
업무를 다루지않는데 스레드가 일하고잇는데 그 스레드를 돕는거를 데몬스레드라고 한다.

그 예시중하나가 자바의 가비지컬렉터이다. 업무를 가지고 있는게 아니라 업무를 돕는역할을 한다.
그래서 다른 스레드가 종료가 되면 본인도 멈춘다.
th2.setPriority(Thread.MIN_PRIORITY);
th2.setDaemon(true);
그래서 우선순위를 낮춰서 같이 설정하는 것이 보통이다.

12. 스레드 그룹 이용하기

스레드를 생성할때 그룹에 포함시켜 생성할 수 있다.
보조업무를 여러개 실행시킬 수 있다. 하나의 업무가 여러개가 왓을때 한번에 관리할 수있는 방법이 필요하다.

인터럽트로 멈출수있는데 여러개를 모두 검사하면서 인터럽트하면 불편하다.
이것을 한번에 할 수있는 것이 스레드 그룹이다.

스레드 6개를 실행시킨다고 해보자
메인이 끝나면 스레드들이 끝나도록 모든 스레드들마다 하나식 인터럽트를 걸어야한다.
매우 불편하다.
ThreadGroup thGroup = new ThreadGroup("print main group");
Thread th1 = new Thread(thGroup, subMain);
스레드 그룹을 만들고 스레드가 생성시에 그룹을 만들어 줄 수 있다.

스레드그룹의 기능
thGroup.list(); 스레드그룹의 리스트
thGroup.activeCount(); 현재 스레드그룹의 활성화된 수를 알 수있다.
thGroup.interrupt(); 인터럽트시키기

스레드그룹의 그룹의 그룹까지 해서 조직을 중첩화할 수있다.
ThreadGroup thGroup = new ThreadGroup("print main group");
ThreadGroup thGroup1 = new ThreadGroup(thGroup, "print sub group1");
ThreadGroup thGroup2 = new ThreadGroup(thGroup, "print sub group2");
각 그룹에 부모그룹을 둘 수 있다.
그래서 각 그룹마다 다른 결과를 줄수도있다.
thGroup1.interrupt();
이러면 1그룹만 멈추고 다른애들은 안멈춘다.

2023.02.17 후기

한번더 공부하는 상속은 더 이해가 잘된다. 스레드 부분은 인강을 듣고 있긴하지만 책 설명이 더 잘 이해되는 것 같다.
책으로 한번 더 봐야할 것 같다.

'기초단계 > JAVA' 카테고리의 다른 글

2023.02.19 Java 복습  (2) 2023.02.19
2023.02.18 Java 복습  (0) 2023.02.19
2023.02.17-1 Java 복습  (1) 2023.02.17
2023.02.16-2 Java 복습  (1) 2023.02.16
2023.02.16-1 Java 복습  (0) 2023.02.16

+ Recent posts