2019.01.09 스레드 Thread, 예외처리

2019. 1. 9. 16:46JAVA

#1 예외처리


예외의 정의

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.exam;
 
public class Test5 {
 
    public static void main(String[] args) {
        System.out.println("--- 프로그램 시작 ---");
        // 예외: 프로그램 실행시간에 발생하는
        //       예기치 못한 오류.
        //       코드로 처리(해결)가능한 오류.
        
        int a = 10, b = 0// 나누는 수가 0일때 ArithmeticException발생안되게
        int result = 0;
        
        if (b == 0) {
            System.out.println("0으로 나눌수 없음");
        } else {
            result = a / b;
        }
        
        System.out.println("나눗셈 결과: "+result);
        
        System.out.println("--- 프로그램 정상종료 ---");
    } // main()
 
}
 
cs



② 예외처리의 방법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.exam;
 
public class Test6 {
 
    public static void main(String[] args) {
        System.out.println("--- 프로그램 시작 ---");
        // 예외 처리
        // try - catch - finally
        
        
        // RuntimeException(실행시간예외)은
        // 자바에서 예외처리를 강제하지 않는다.
        // 그러므로 예외처리가 선택적이다.
        
        // RuntimeException - ArithmeticException
        //                  - NullPointerException
        //                  - ...
        
        int a = 10, b = 2// b = 0
        int result = 0;
        
        String str = "";
        
        int[] array = { 123 };
        
        try {
            // 예외가 발생할것 같은 문장
            result = a / b; // ArithmeticException
            
            int length = str.length(); // NullPointerException
            
            array[3= 4// ArrayIndexOutOfBoundsException
            
        } catch (ArithmeticException e) { // 작은 글러브
            e.printStackTrace();
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (RuntimeException e) { // 큰 글러브
            e.printStackTrace();
        } catch (Exception e) { // 아주 큰 글러브
            e.printStackTrace();
        } finally {
            System.out.println("예외발생 여부 상관없이 정리작업");
        }
        
        System.out.println("나눗셈 결과: "+result);
        
        
        System.out.println("--- 프로그램 정상종료 ---");
    } // main()
 
}
 
cs




③ 예외처리의 방법2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.exam;
 
class ExcepTest {
    
    /*int a;
    int b;
    a = 10;
    b = 20;
    System.out.println(a+b);*/
    
    int methodD() {
        // try - finally 는 예외처리랑 관계없음
        // 
        try {
            return 10;
        } finally {
            System.out.println("출력");
        }
    }
    
    
    void methodC() throws Exception {
        methodB();
    }
    
    void methodB() throws Exception {
        methodA(50);
    }
    
    void methodA(int num) throws Exception {
        if (num < 100) {
            throw new Exception("num값이 100보다 작다.");
            
            // 1) 예외를 내부적으로 직접처리하는 방법
//            try {
//                throw new Exception("num값이 100보다 작다.");
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
        }
    }
}
 
 
public class Test7 {
 
    public static void main(String[] args) /*throws Exception*/ {
        ExcepTest test = new ExcepTest();
        try {
            test.methodC();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        int num = test.methodD();
        System.out.println(num);
        
        System.out.println("--- 프로그램 정상종료 ---");
    } // main();
 
}
 
cs




#2 스레드 Thread


① Thread의 기본형태

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.example;
 
/* 스레드 Thread */
class Go {
    void go() {
        while (true) {// 무한반복
            System.out.println("go");
        }
    }
}// Go()
 
class Come {
    void come() {
        while (true) {// 무한반복
            System.out.println("come");
        }
    }
 
}// Come()
 
public class Test3 {
    public static void main(String[] args) {
        Go g = new Go();
        Come c = new Come();
        
        g.go(); 
        c.come();
    
    }// main()
 
}
 
cs



②Multi Thread 방법1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.example;
/* 멀티 스레드 Multi Thread 방법1*/
class Go1 extends Thread{
    // 작업스레드의 시작 (진입점)메소드는 run()이다.
    @Override
    public void run() {
        go1();
    }
    void go1() {
        while (true) {// 무한반복
            System.out.println("go");
        }
        
    }
}// Go1()
 
class Come1 extends Thread{
    @Override
    public void run() {
        come1();
        }
    void come1() {
        while (true) {// 무한반복
            System.out.println("come");
        }
    }
 
}// Come2()
public class Test4 {
    /*     < 주(main) 스레드와 보조(Daemon) 스레드 >
         스레드는 주 스레드와 보조 스레드로 나뉜다.
           주 스레드는 1개라도 동작 중이면 프로그램 종료가 되지 않는다.
           하지만, 보조 스레드는 주 스레드를 보조하는 역할이므로 주 스레드가 종료되면
           보조 스레드도 함께 종료된다.*/
    public static void main(String[] args) {
        /* 멀티 스레드 생성방법1.
             1. Thread 클래스 상속
                run() 메소드 오버라이딩
                   스레드 객체.start(); 스레드 시작*/
        /* 스레드는 Thread타입의 객체이다.
         * 스레드 객체가 생성되면 해당 객체만의 스택이 생성된다. */
        Go1 g1 = new Go1(); // 스택 생성후 준비됨
        Come1 c1 = new Come1(); // 스택 생성후 준비됨
        
        /*스레드 제어는 사용자가 하지않고 JVM이 제어한다. 
          JVM한테 스레드 시작을 부탁하는 메소드가 start()이다.*/
        g1.start();
        c1.start(); // ▶출력  : come과 go가 반복되며 출력된다.
 
    }//main()
 
}
 
cs


Multi Thread 방법2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.example;
/* 멀티 스레드 Multi Thread 방법2: Runnable 인터페이스 방식1 */
 
// [작업 내용]을 가진 클래스
class goTask implements Runnable{ 
 
    @Override
    public void run() {
        while(true) {
            System.out.println("go");
        }
 
    }
}//goTask()
 
class comeTask implements Runnable{
 
    @Override
    public void run() {
        come();
        
    }
    void come() {
        while(true) {
        System.out.println("come");
        }
    }
}//comeTask()
    
 
public class Test5 {
    public static void main(String[] args) {
        /* 멀티 스레드 생성방법2
         * 2. Runnable 인터페이스 구현
               run() 메소드 오버라이딩
               Thread 객체 생성 -> Runnable 구현객체를 사용하도록 전달
                 스레드 객체.start() 스레드 시작*/
        // Thread는 일꾼 객체 , Runnable구현 객체는 일꾼이 할 일이 정의되어 있는 객체
        Runnable goTask = new goTask(); //업 캐스팅
        Thread t1 = new Thread(goTask); // 일꾼에게 할 일을 등록, 콜백패턴
        
        Runnable comeTask = new comeTask();
        Thread t2 = new Thread(comeTask);
        
        t1.start(); // 일꾼이 일을 시작하다록 JVM에게 부탁
        t2.start(); // JVM은 스레드 준비가 완료되면 스레드 객체의 run()메소드를 호출
 
    }//main()
 
}
 
cs



Multi Thread 방법3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.example;
 
/* 멀티 스레드 Multi Thread 방법3 :Runnable 인터페이스 방식2*/
public class Test6 {
 
    public static void main(String[] args) {
        // Runnable 방식으로 스레드 사용
        // 함수적 인터페이스 : 추상메소드 1개 가진 인터페이스 → 람다식 활용가능
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println("작업스레드 " + i);
                }
            }
        }).start();
        
        //람다식 활용
        new Thread(()->{
            for(int i= 0; i<3; i++) {
                System.out.println("람다식 작업 스레드"+i);
            }
        }).start();
        
        //메인 스레드
        for(int i=0; i<3; i++) {
            System.out.println("메인스레드 "+i);
        }
    }//main()
 
}
 
cs


#3 스레드 Thread의 종류 및 우선순위


① 메인 스레드(main thread)와 보조 스레드(daemon thread)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.example;
/*메인 스레드와 보조스레드의 위치*/
import java.awt.Toolkit;
public class Test7 {
 
    public static void main(String[] args) {
        /*
         * 프로그램이 실행되면 main thread가 생성되고 main thread에서 main()메소드가 호출함
         */
        Thread thread = new Thread(() -> { // run()메소드가 생략되어있다
            Toolkit toolkit = Toolkit.getDefaultToolkit();
            for (int i= 0; i < 5; i++) {
                toolkit.beep();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.setDaemon(true);// 보조스레드 설정
        thread.start();
        /* main thread가 끝난 상태에서 Daemon thread가 실행되지 않기 때문에
             Daemon thread가 먼저 선언되어야 한다.*/
        
        for (int i = 0; i < 5; i++) {
            System.out.println("띵~");
            try {
                Thread.sleep(500);
            } catch (Exception e) {
                e.printStackTrace();
            } // 예외처리가필요
        }
        
    }// main()
 
}
 
cs


②  스레드의 이름 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.example;
/* 스레드의 이름*/
public class Test8 {
 
    public static void main(String[] args) {
        Thread mainThread = Thread.currentThread();
        System.out.println(mainThread.getName()); // 스레드의 이름 받아오기
        
        mainThread.setName("major thread"); // 스레드의 이름 재정의
        System.out.println(mainThread.getName());
        
        final Thread t1 = new Thread(new Runnable() {
 
            @Override
            public void run() {
                for(int i=0; i<2; i++) {
                    System.out.println(i+"");
                }
            }
            
        });
        System.out.println(t1.getName());
        t1.setName("작업스레드1");
        t1.start();
    }//main()
 
}
 
cs



④ 스레드 우선순위

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.example;
 
public class Test9 {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        
        /* 스레드 우선순위 
           :우선순위 방식에서 우선순위는 1에서 10까지 부여되는데,
            1이 가장 낮은 우선순위,10이 가장 높은 우선순위이다.
                우선순위를 부여하지 않으면 모든 클레스들은 기본적으로 5의 우선순위를 할당받는다. */
        
        System.out.println(Thread.currentThread().getPriority()); // 우선순위 값을 int로 리턴
        System.out.println(Thread.MAX_PRIORITY); // 최대 우선순위 :10
        System.out.println(Thread.MIN_PRIORITY); // 최소 우선순위 :1
        System.out.println(Thread.NORM_PRIORITY); // 중간 우선순위 :5
        
        Thread.currentThread().setPriority(8); // 우선순위를 설정
    }//main()
}
 
cs

 


#4 스레드를 활용한 GUI 시계


① RootController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package com.exam.app.view;
 
import java.net.URL;
import java.util.ResourceBundle;
 
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
 
public class RootController implements Initializable {
    @FXML
    private Label label;
    @FXML
    private Button btnStart, btnStop;
 
    private int count = 0// 카운트 필드
    private Thread t;
 
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        btnStart.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                startCount(event);
 
            }
        });
 
        btnStop.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                if (t == null) {
                    return;
                } else {
                    t.interrupt(); // 권장되는 스레드 종료방식
                }
 
            }
        });
    public void startCount(ActionEvent event) {
        t = new Thread(new Runnable() {
 
            @Override
            public void run() {
                startCount1();
 
            }
        });
        t.setDaemon(true); // 보조 스레드 지정
        t.start();
    }// startCount()
 
    public void startCount1() {
        while (true) {
            if (Thread.interrupted()) {
                break;
            }
            Platform.runLater(new Runnable() {
 
                @Override
                public void run() {
                    label.setText(count + "");
                }
            });
            try {
                Thread.sleep(1000);
                /*
                 * 일시정지되는 동안 Interrupted()가 호출되면 InterruptedException이 발생됨
                 */
            } catch (InterruptedException e) {
                break// 인터럽트 발생시 발생종료
            }
            count++;
        }
 
    }// run1
}
 
cs


② Main class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.exam.app;
 
import java.io.IOException;
 
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
 
public class MainApp extends Application {
 
    @Override
    public void start(Stage primaryStage) {
        Scene scene= null;
        try { //  단축키 : alt + shift + z 
            // fxml 파일로부터 컨테이너 가져오기
            Parent root =FXMLLoader.load(getClass().getResource("view/Root.fxml"));
            scene = new Scene(root); // 화면 생성, import 단축키 :ctrl +shift +o
        } catch (IOException e) {
            e.printStackTrace();
        }    
        // 윈도우 창에 부착
        primaryStage.setScene(scene);
        primaryStage.setTitle("창 제목");
        primaryStage.setResizable(false);
        primaryStage.show();
 
    }//start()
 
    public static void main(String[] args) {
        
        launch(args);
    }
}
 
cs



cf) 버튼동작없이 화면출력만 할 경우


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        Thread t1 = new Thread(() -> {
            while (true) {
                // ▼ int->String으로 변환 ,사용자의 눈에 보이는 컨트롤에 대한 수정은 작업스레드에서 할수 없다.
                Platform.runLater(() -> {
                    label.setText(String.valueOf(count));
                });
                try {
                    Thread.sleep(1000);// 1000ms , 1초동안 멈추었다 다시실행
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count++;
            }
 
        });
        /*
         * main Thread(주스레드)가 종료될 때 같이 종료되게 하기 위해 Daemon Thread(보조 스레드)로 설정해준다.
         */
        t1.setDaemon(true);// 보조스레드로 설정
        t1.start();
cs