Thread4

제이·2023년 3월 16일
post-thumbnail

interrupt()

class Dummy {
	public synchronized void todo() {
		try {
			System.out.println("start....");
			wait();
		}catch(InterruptedException e) {
			System.out.println("interrupted");
			System.out.println("t1(run) :" 
            + Thread.currentThread().isInterrupted());
		}
	}
}
public class InterruptEx {
	public static void main(String[] args) {
		final Dummy d = new Dummy();
		Thread t1 = new Thread() {
			@Override
			public void run() {
				d.todo();
				System.out.println("i'm dead");
			}
		};
		t1.start();
		t1.interrupt();
        //호출되면 스레드는 실행불가상태에서 대기열로 돌아온다. 
	}
}
//결과
start....
interrupted
t1(run) :false
i'm dead

interrupt()

  • interrupt()되면, 스레드는 실행불가상태(not runnable)에서 대기열(runnable)로 돌아온다.
    실행불가상태가 중단이 된다. 실행불가를 실행가능한 상태로 돌려준다.
    실행불가상태가 아니면 아무일도 안 일어난다.

  • 그런데, 실행불가상태(not runnable)로 빠져있는 스레드가 대기열(runnable)로 들어와서(깨어난 후에) 다시 run상태로 가면 예외처리된 것으로 처리한다.
    예외가 되었다고 생각되고, catch문에 있는 내용이 출력된다.

  • 코드설명
    main창에서 t.start()해주고, t.interrupt()까지 해줘서 t스레드가 탈출권을 가지게 된다. 그래서 not runnable에서 바로 나오고, 다시 runnable-> run으로 가게 되는데 그럼 탈출권을 쓰고 나왔기 때문에 예외가 발생해서 catch문안에 값이 출력되게 된다.

  • 결과 창을 보면, t1(run) :false
    wait() 걸리기 전이면 true가 나온다. 실행불가 상태엿다가 다시 깨어나면 정보가 초기화가 된다. interrupted를 받았다는 정보를 없애고 false로 바꾼다.

  • 미리 interrupt(무인도탈출권)를 받으면은 실행하는 도중에 실행불가 상태로 빠지면, 미리 받았기 때문에 실행불가에 안 갇혀있고 대기열로 돌아온다.

  • 내가 선택한 놈을 깨울 수 있는데, 그 타이밍을 맞출 수 있을 것인가가 고민이다.
    동작하는 순번 등이 계속 바뀌고, 내가 의도한 것은 갇혀있기를 원했는데, 타이밍이 안맞으면 걔가 안갇힐 수 있다. 예측이 안된다.
    되게 조심해서 써야한다. 100프로 갇힌다고 생각했을 때 골라서 인터럽트 사용할 수 있다.

  • 인터럽트 막 사용하지 않기.

  • 스윙컴포넌트는 전부 다 스레드세이프하지 않아서 스윙쓸 때 스레드 조심해야한다. 특히, 오래 걸리는 작업(뺑뺑이 돌리는 거?)
  • isInterrupted() : interrupt 되었는 지 물어보는 메서드(boolean)
  • interruptException - 메소드에 의해서 실행불가 상태로 바꿔버리는 것들이 이 예외를 발생시킨다.

interrupt Ex1

public class InterruptEx1 {
	public static void main(String[] args) {
		Thread t1 = new Thread() {
			@Override
			public void run() {
				try {
					System.out.println("isInterrupted:" 
                    + isInterrupted());
					System.out.println("sleep...");
					//1분간 잠든다.. run -> not runnable
					Thread.sleep(1000*6);
				}catch(InterruptedException e) {
					//interrupedException 처리되는 순간
					//interrupt받은 기록이 사라진다.
					System.out.println("wake up");
					System.out.println("isInterruped:" 
                    + isInterrupted());
				}
				for(int i = 0 ; i<10 ; i++) {
					System.out.println(i);
				}
			}
		};
		t1.start();
		//t1.state : not runnable -> runnable
		🌜try {
			Thread.sleep(5000);
		}catch (Exception e) {}🌛
		t1.interrupt();
	}
}
//결과
isInterruped:true	여기서는 true
sleep...
wake up
isInterruped:false		여기는 false
0
1
2
3
4
5
6
7
8
9

interrupt 예시1

  • 원래는 재울려고 이 코드를 만들어 놨는데, 애가 깸. 1분동안 잠들지 않고 바로 일어남. - 나의 생각과 다르게 코드가 작동.

  • 코드설명
    main이 먼저 생성되었으니까 run에 가서 실행한다. start()시켜서 t1스레드를 runnable상태로 만든다. 그리고 try문을 만나서 잠든다. 그 사이 t1이 run상태가 되어서 run()메서드를 읽는다. 그리고 잠든다. 그리고 main이 일어나서 interrupt()를 해주고, 그리고 main은 죽는다. 그리고 t1은 살아나서 run()으로 가지만 interrupt로 일어나서 예외가 발생한다. 그래서 wakeup하고 이미 탈출권을 썼으니까 false로 나온다.

  • 🌜 부분의 코드(try-catch)를 작성하면 main이 잠깐 잠든 사이에 t1이 run 상태로 가게 된다. 그러면 interrupted되지 않았으니까 false로 나온다. 이렇게 짜는 게 쉽지 않다.

  • 먜 ) t1.start()랑 t1.interrupt()는 main이 다 하는 거다.

interrupted()

public class InterruptTest {
	public static void main(String[] args) {
		Thread t = new Thread() {
			public void run() {
				try {
					System.out.println("try - isInterrupted : " 
                    + isInterrupted());
                    `
					//인터럽트 받은 기록이 초기화됨(false)
					🌜System.out.println(
                    "try - interrupted : " + Thread.interrupted()
                    );	
					// true가 나옴. 🌛
                    `
					System.out.println("ok");
					Thread.sleep(4000);
				}catch(InterruptedException e){
					System.out.println(
                    "catch - isInterrupted :" + isInterrupted());
				}
			}
		};
		t.start();
		t.interrupt();
		System.out.println(
        "isInterrupted :" 
        + t.isInterrupted());
		try {
			Thread.sleep(1000);
		}catch(Exception e) {}
		System.out.println("isInterrupted : " + t.isInterrupted());
	}
}
//결과
isInterrupted :true
try - isInterrupted : true
try - isInterrupted : true
ok
isInterrupted : false

interrupted()

🌜🌛 이부분 보면, true가 나온다. catch안의 구문이 안나옴. static메소드.
이거는 수행한 스레드(t1)가 수행하게 되면, 인터럽트를 받았는지 안받았는지 알려주고, 만약에 인터럽트를 받았으면 true를 리턴하고 인터럽트 받았던 기록을 없애버린다. 4초 잠들었다가 catch문 걍 넘어간다.
수행한 t1이 초기화되는 거.
💡팁) println안에 명령어를 넣어도 명령입력이 된 것으로 작동을 하긴 한다.

  • Thread.interrupted()
    :인터럽트를 받았다면 받았던 기록을 없애버릴 때 쓴다.
    static 메소드다.
  • 코드설명
    Thread.interrupted()를 했기때문에, interrupt()를 받았던 기억을 없애버리기때문에, 자다가 다시 ㅅ

interrupt Ex3

public class InterruptEx2 {
	public static void main(String[] args) {
		Thread t1 =  new Thread() {
			@Override
			public void run() {
				long count = 0;
				while(!isInterrupted()) {	//어떤 스레드가 멈추는 게 가능하다.
					//뭔가 한다.
					//반복문 안에서 해야할 일들이 엄청 오래 걸리는 게 있을 수 있다. -> 인터럽트 날려도 구문의 특성 상 while문 안이 다 동작해야지 조건문이 된다. 
					count++;
				}
				System.out.println("interrupted -> count = " + count);
				System.out.println("isInterrupted :" + isInterrupted());
				//...wait,sleep,join...
			}
		};
		t1.start();
		try {
			Thread.sleep(1000);
		}catch(Exception e) {	
		}
		t1.interrupt();
		t1.isInterrupted();
	}
}
//interrupted -> count = 2056881689
//isInterrupted :true

이부분 잘 모르겠음.

  • 어제 복습
    객체가 lock을 얻는 세가지 방법
    1.그냥 일반 싱크로나이즈드 메소드에 진입 - lock의 주체 : this.
    2.싱크로 블록에 진입했을 때 -lock의 주체 : 설정할 수 있다.
    3.static 싱크로나이즈드 메소드 -lock의 주체 : 거기 속해 있는 클래스의 클래스 객체
    4.lock얻었을 때만 불러올 수 있다. 그거 안하고 하면은 예외 발생한다.
    5.wait()되면, 이렇게 됐다는 얘기는 lock을 가지고 있었다는 것. - lock 풀고 실행불가능상태로.
    6.notify가 호출되면 대기열로 돌아온다.

정리

  • interrupt() : 해당 쓰레드에게 인터럽트를 건다. 스레드는 실행불가상태(not runnable)에서 대기열(runnable)로 돌아온다.
    실행불가를 실행가능한 상태로 돌려준다.
  • t.isinterrupted() : thread t가 인터럽트를 받았는지 확인한다.
  • interrupted() : 현재쓰레드(static)가 인터럽트 받았는지 확인하고 상태를 초기화한다.

03.16수업

profile
Hello :)

0개의 댓글