다연이네

[days26] 스레드 - 동기화의 필요성 본문

Java

[days26] 스레드 - 동기화의 필요성

 다연  2020. 10. 26. 23:44
반응형
package days26;

public class Ex09 {

	public static void main(String[] args) {
		//문제 - 동기화
		// 이름을 출력하는 스레드 선언: PrintWorker
		// 이름을 출력하는 클래스: PrintMachine (기계는 1대라서 모든 스레드가 공유해서 사용) 공유자원
		
		PrintMachine machine = new PrintMachine(); //머신1대(공유자원)
		
		PrintWorker t1 = new PrintWorker("배다연", machine);
		PrintWorker t2 = new PrintWorker("김동준", machine);
		PrintWorker t3 = new PrintWorker("남도산", machine);
		PrintWorker t4 = new PrintWorker("서달미", machine);
		PrintWorker t5 = new PrintWorker("한지평", machine);
		
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
		//[[[[[***************김배남서한동다지도달준연산평미***************]]]]]
		//=> 동기화(lock)필요
		
		

		

	}

}
class PrintWorker extends Thread{
	String name = null;
	PrintMachine machine = null;
	public PrintWorker() {}
	public PrintWorker(String name, PrintMachine machine) {
		this.name = name;
		this.machine = machine;
	}
	
	@Override
	public void run() {
		this.machine.printName(name);
		}
	
}
class PrintMachine{
	public void printName(String name) {
		//[***홍길동***] 한자씩 찍기로 
		
		try {
			System.out.print("[");
			Thread.sleep(500); // 이거 코딩하고 try~catch로 묶은 다음 코딩 트라이 안에 다 넣기 
			System.out.print("***");
			Thread.sleep(500);
			for (int i = 0; i < name.length(); i++) {
				System.out.print(name.charAt(i));
				Thread.sleep(500);
			}
			System.out.print("***");
			Thread.sleep(500);
			System.out.print("]");
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	
		
	}
}



출력값

[[[[[***************김배남서한동다지도달준연산평미***************]]]]]

 

동기화 1) run()에 동기화구문 추가하기 **동기화 객체를 괄호 안에 써준다**

	@Override
	public void run() {
		synchronized (this.machine) {
			this.machine.printName(name);
		}
	}

동기화 2)  try~catch구문 감싸기

class PrintMachine{	
	public void printName(String name) {
		synchronized (this) { 
			try {}
				
			catch (InterruptedException e) {}
		}

 

동기화 3)  public과 void 사이에 넣기

class PrintMachine{	
	public synchronized void printName(String name) {
			try {}
			 catch (InterruptedException e) {}
    }
 }

 

1. void interrupt()  - 스레드 작업 중지하라고 요청만 한다(실제 중지는 x), 그저 스레드의 interrupted상태를 바꾸는 것
2. static boolean interrupted() - interrupt() 메소드가 호출되었는지 여부 T/F로 돌림
3. boolean isInterrupted() - 현재 interrupted 상태 반환

package days26;

import javax.swing.JOptionPane;

public class Ex10 {

	public static void main(String[] args) {
		
		//메인스레드
		ThreadEx13_1 th1 = new ThreadEx13_1();
		th1.start();
		String input = JOptionPane.showInputDialog("아무 값이나 입력하세요 ");
		System.out.println("입력하신 값은 "+input+"입니다.");
		th1.interrupt();	//t1스레드 중지 요청 - interrupt() 호출하면 interrupted 상태가 true가 된다
		System.out.println("isInterrupted() : "+th1.isInterrupted() ); //true 중지 했는지 안했는지 상태값 찍기
 	}

}

class ThreadEx13_1 extends Thread{
	public void run() {
		int i = 10;
		
		while (i!=0 && !isInterrupted()) { //값입력해서 확인 누르면 isInterrupted()만나 while 빠져나감
			System.out.println(i--);
			for (long x=0; x<2500000000L; x++) ; //시간지연 (그냥 아무일도 안하는데 이만큼 시간이 가고 있다는 뜻)
			
		}
		System.out.println("카운트 종료");
		
	}
}

InputDialog에 값을 입력하면 interrupt에 의해 while문이 종료되어 카운트가 종료된다.

 

위의 코딩을 sleep()을 이용하고 싶다면?

while (i!=0 && !isInterrupted()) { 
			System.out.println(i--); 
			try {
				Thread.sleep(2000); 
			} catch (Exception e) {
				
				 interrupt() ;
			}

만약 catch문에 interrupt()가 없다면 숫자를 카운트 끝날때까지 다 찍는다.
main에서 중지요청을 보냈지만 효과가 없는 이유는 무엇일까?
-> 만약 값을 입력하면 main스레스에서 t1.interrupt() 요청이 들어오는데, 마침 sleep상태에 있었다면 (확률99.9%) 
(= 대기상황(sleep)에 중지요청을 하면) 예외가 발생한다( e.printStackTrace(); ).

예외를 출력하라는 알고리즘도 없기 때문애 그냥 무시한채 진행한것처럼 보인다.

//결론: catch문 안에 interrupt() 넣어줘야한다

 

1. suspend() 일시멈춤 - 끄집어내줄때까지는 일 못함
2. resume() 다시시작 - 끄집어내줌
3. stop() 스레드 종료 - 강제종료
=> 모두 폐기될 것(사용금지)

package days26;

public class Ex11 {

	public static void main(String[] args) {
		
		RunImpleEx15 r = new RunImpleEx15();
		Thread th1 = new Thread(r, "*");
		Thread th2 = new Thread(r, "**");
		Thread th3 = new Thread(r, "***");
		
		th1.start();
		th2.start();
		th3.start();
		//main스레드가 처리중
		
		
		try {
			
			Thread.sleep(2000);
			
			th1.suspend(); //실행불가 (메인이 실행시켜야하는데 메인이 쉬고있으니까)
			Thread.sleep(2000);
		
			th2.suspend();
			Thread.sleep(3000);
			th1.resume();
			Thread.sleep(3000);
			th1.stop();
			th2.stop();
			Thread.sleep(2000);
			th3.stop();
		} catch (InterruptedException e) {}
		

	}

}

class RunImpleEx15 implements Runnable{
	public void run() {
		
		while(true) {//스레드가 안죽는다(무한루프니까) -> 강제종료 메소드 호출해야함(stop)
			System.out.println(Thread.currentThread().getName()); //출력하고
			try {
				Thread.sleep(1000); //1초 NotRunnable 상태로 
			} catch (InterruptedException e) {	}
		}
	}
}

위 알고리즘 흐름 알기 ***

반응형

'Java' 카테고리의 다른 글

[days27] 동기화  (0) 2020.10.27
[days27] 스레드 강제종료  (0) 2020.10.27
[days26] 스레드 예제  (0) 2020.10.26
[days26] 스레드(Thread)  (0) 2020.10.26
[days26] 직렬화(Serialization) - ObjectInputStream/ObjectOutputStream  (0) 2020.10.26
Comments