-
[자바기초] 멀티쓰레드(MultiThread), 임계영역(Critical section) 정리노트º Language º/Java 2023. 4. 10. 20:53
* 멀티 쓰레드란?
- 두개 이상의 객체가 어떠한 메소드를 수행함에 있어 가능하면 공평하게 실행되게끔 스케쥴링 해주는 기술이에요.
일반적으로는 메소드를 호출하면 호출한 순서대로 동작을 하게 됩니다.
코드로 살펴보면,
class Person{ ... public vod sayHello(){ for(int i=1; i<=10; i++){ System.out.println("안녕"+name); } } } Person kim = new Person("김유신"); Person lee = new Person("이순신"); kim.sayHello(); lee.sayHello();
> kim 의 sayHello() 메소드를 먼저 호출했기 때문에 kim의 sayHello의 내용이 다 끝나야 lee에게 기회가 옵니다.
여기서 문제는.. kim의 sayHello()를 동작하다가 문제가 발생된다면? lee에게는 영영 기회가 오지 않을수 있어요!
그러므로 두개의 객체가 가능하면 공평하게 실행시키고자 할 때 "멀티쓰레드" 프로그래밍을 해야 합니다.
* Thread 클래스와 Runnable 인터페이스
- 자바에서는 "멀티 쓰레드"를 위해 Thread클래스와 Runnable인터페이스를 제공합니다.
1. Thread 클래스를 이용하는 방법
1) Thread 클래스를 상속받아 클래스를 만든다.2) run메소드를 오버라이딩 하여 그 안에 공평하게 실행시키고자하는 명령들을 써준다.
3) Thread를 가동시키기 위하여 .start() 메소드를 호출시킨다.( .run()으로 호출하면 메소드처럼 불려오는 것이기에 멀티쓰레드 호출 방식이 아닙니다.)
class Person extends Thread { public void run(){ //공평하게 실행시키고자 하는 명령어(들) for(int i=1; i<=10; i++){ System.out.println("안녕"+name); } } } Person kim = new Person(); Person lee = new Person(); kim.start(); lee.start(); //lee.run(); 이렇게 작성하면 안됩니다.
> 위에 코드처럼 Thread를 이용하여 run메소드를 오버라이딩 하여 사용하면 kim과 lee에게 공평하게 번갈아가며 실행이 되게끔 스케줄링이 됩니다.
2. Runnable 인터페이스를 이용하는 방법
1) Runnable 인터페이스를 구현한 클래스를 만든다.2) run을 오버라이딩 하여 공평하게 실행시키고자 하는 명령어(들)을 써준다.
3) 객체를 생성하고 start()를 바로 호출할 수 없고 Thread로 포장해서 start로 호출해야 한다.
class Person implements Runnable{ public void run(){ //공평하게 실행시킬 명령어 (들) for(int i=1; i<=10; i++){ System.out.println("안녕"+name); } } } Person p = new Person("김유신"); Person p1 = new Person("이순신"); //p.start(); //p1.start(); -> Runnable 인터페이스로 구현한 객체라서 start를 바로 못 씁니다. new Thread(p).start(); new Thread(p1).start(); -> Thread 객체로 포장 한 후 start 객체를 사용합니다.
> 위에 코드처럼 Runnable 인터페이스를 이용하여 run메소드를 오버라이딩 하여 사용하는 경우에도 kim과 lee에게 공평하게 번갈아가며 실행이 되게끔 스케줄링이 됩니다.
+ 인터페이스(interface) : 완전 추상 (추상메소드와 상수값만을 가짐), 오버라이딩 필수
* 임계 영역 (critical section)
- 두 개이상의 쓰레드 객체가 공유하는 자원이 있을 때 한번에 하나의 쓰레드에게만 접근을 허용하는 영역을 말합니다.
(즉, 공유자원이지만 동시접속은 불가한 영역)
* synchronized
- 이것을 위해 자바에서는 임계 영역에 접근하는 메소드 이름 앞에 "synchronized" 키워드를 써주어 임계영역을 설명합니다. 이렇게 하면 한번에 하나의 쓰레드 에게만 접근이 됩니다.
* 쓰레드 사이의 통신
- 쓰레드를 가동 시키면 '가능하면' 공평하게 실행이 되게끔 스케쥴링 해줍니다. (그렇지 않을 수도 있다는 말입니다.)
그런데 만약 두개 이상의 객체가 반드시 1:1로 동작하게 하려면 쓰레드 사이에 통신을 이용합니다.
쓰레드 사이의 통신을 위해서는 오브젝트 클래스의 wait 메소드와 notify 메소드를 이용합니다. (예외처리해야함)package product; import java.util.Random; public class Product { private int num; private boolean isNew; public synchronized void useNumber() { while ( isNew == false) { try {wait();} catch (Exception e) {} } System.out.println("소비자가 물건을 소비했습니다"+num); isNew = false; notify(); } public synchronized void makeNumber() { Random random = new Random(); while(isNew == true) { try {wait();} catch (Exception e) {} } num = random.nextInt(100)+1; System.out.println("생산자가 새로운 물건은 생성했습니다"+num); isNew = true; notify(); } }
> 멀티 쓰레드 환경에서 이처럼 wait와 notify를 통해 임계영역을 동기화하여 사용해야 오류가 없습니다.
* Thread에게 우선순위를 설정하기
- 최고의 우선순위를 설정했다고 해서 반드시 그것이 작업을 먼저 완료하는 것이 보장되지는 않아요.
요청을 하는 것 뿐입니다. 그냥 '시스템 상황에 따라 가능하면 일찍 끝내주세요'라고 하는 것입니다.(확실한 우선순위가 표현되는 것이 아니기 때문에 많이 사용되지는 않습니다만 시험을 위해 알아둡니다.)- 최고 우선순위 : MAX_PRIORITY ==> 10
- 최저 우선순위 : MIN_PRIORITY ==> 1- 노멀 우선순위 : NORM_PRIORITY ==> 5 (설정 안해놓으면 기본적으로 우선순위 5로 적용됩니다.)
setPriority(Thread.MAX_PRIORITY) setPriority(10)
> 이렇게 두가지의 방법으로 사용 가능합니다.
'º Language º > Java' 카테고리의 다른 글
[자바기초] GUI 네트워크 통신 (TCP방식, UDP방식) 정리노트 (0) 2023.04.13 [자바기초] 예외 처리(Exception) 정리노트 (0) 2023.04.06 [자바기초] 생성자를 만드는 이유 정리노트 (0) 2023.04.02 [자바기초] 날짜 클래스 GregorianCalender 정리노트 (0) 2023.04.01 [자바기초] 컬렉션 프레임워크의 종류 (3가지), 제네릭 정리노트 (0) 2023.03.29