-
1. 멀티스레드의 개념
- 프로세스: 운영체제에서 실행중인 프로그램
- 멀티 태스킹: 두 가지 이상의 작업을 동시에 처리하는 것 (멀티프로세스,멀티스레드)
- 스레드: 코드의 실행 흐름, 하나의 프로세스에서 멀티 태스킹
> 멀티 프로세스 환경에서 하나의 프로세스의 오류가 다른 프로세스에 영향x
> 멀티 스레드는 하나의 스레드 예외는 다른 스레드에 영향
1.2 main 스레드
- 자바 프로그램은 메인 스레드가 main()메서드의 시작과 함께 실행된다.
- 하나의 스레드는 첫 코드부터 순차적으로 실행, 마지막 코드 실행 혹은 return문을 만나면 종료
- 메인 스레드에서 추가 작업 스레드를 만들어서 실행 가능
- 멀티 스레드에서는 작업 중인 스레드가 남아있으면, 프로세스 종료하지 않는다.
2. 작업 스레드의 생성
- 멀티 스레드 프로그램은 몇 개의 작업을 병렬로 실행할지 결정하고, 작업별 스레드를 생성해야함
2.1 Thread클래스 생성
Thread thread = new Thread(Runnable r); //> Runnable 인터페이스 구현체를 매개변수로 생성 //> 함수형 인터페이스임 람다식 가능 (매개변수x return x) //> 익명 클래스 가능 thread.start //()호출 Thread thread = new Thread(){ @Override //.. } Thread thread = new Thread(()->{ ..// }) public class MyThread extends Thread{ @Override public void run(){ //.. } }
- 스레드 이름 설정
thread.setName("") //스레드 이름설정 Thread.currentThread().getName() // 실행중인 스레드 이름 //getName()인 Thread의 인스턴스변수
3. 스레드 상태 (실행제어)
- 스레드 객체를 생성하고 start메서드를 실행하면, 스레드는 실행 대기 상태가 된다.
- 실행 대기하는 스레드는 CPU의 스케쥴링에 따라 CPU를 점유하고 run()메서드를 실행한다.(실행상태)
- 모든 스레드는 실행 대기와 실행 상태를 번갈아가며 자신의 run()을 완료한다.
- run()이 종료되면, 스레드는 종료상태가 된다.
> 실행 -> 일시정지 상태로 갈 수 있는데, 이는 스레드를 실행할 수 없는 상태이다. 다시 실행하기 위해서는 일시정지에서 실행대기로 가야함
3.1 스레드 실행 제어 메서드
- 일시 정지로 보냄
sleep(long mills) 주어진 시간동안 스레드 일시 정지 상태로 만든다 -> 시간이 지나면 자동 실행대기
static메서드join() join()호출한 스레드는 일시정지 -> join()메서드 가진 스레드 종료시 실행대기
*다른스레드객체.join()wait() 동기화 블럭 내에서 스레드 일시정지 (Object 메서드) - 일시 정지에서 벗어남
interrupt() 일시정지 상태일 경우, InterruptedException을 발생시켜 실행 대기 혹인 종료로 만듦
*다른스레드가 일시정지상태인 스레드를 깨워주는 것notify()
notifyAll()wait()메서드로 인해 일시정지된 스레드 실행대기 (Object 메서드) - 양보
yield() - 실행 상태에서 다른 스레드에게 실행 양보하고 실행 대기가 된다. (static)
public static void main(String[] args) { ThA tha = new ThA(); tha.start(); tha.setThre(Thread.currentThread()); try { tha.join(); } catch (InterruptedException e) { } System.out.println("tha.getSum() = " + tha.getSum()); } //join(); -> tha내부에서 main스레드의 일시정지 풀도록 interrupt()발생시키면 풀림 public void run(){ while(true){ if(work)System.out.println(getName() +" 작업처리중"); else { System.out.println(getName()+"양보"); Thread.yield(); } } } //양보 (static 메서드들은 currentThread에 적용)
3.2 스레드 동기화를 이용한 실행제어
- 멀티스레드는 하나의 객체를 공유할 수 있다.
- 다른 스레드에 의해 객체 내부 데이터가 쉽게 변경될 수 있기 때문에 의도하지않은 결과 불러올 수 있다.
- 한 스레드 작업이 끝날 때 까지 객체에 잠금을 걸 수 있다. > 동시화 메스드와 블록
- 객체 내부에 동기화 메서드와 블럭이 여러개가 있다면, 스레드가 이들 중 하나 실행시
다른 동기화 메서드 및 블럭 실행 불가하다.
> synchronized 키워드 -> 동기화 메서드 및 블럭 생성
public synchronized void met(){ } public void method(){ sychronized(공유객체){ //동기화 블럭 // 단 하나의 스레드만 실행가능 } //여러스레드에서 실행가능 }
public synchronized void setMemory(int memory){ this.memory= memory; try{ Thread.sleep(5000); }catch (InterruptedException e){ } System.out.println(Thread.currentThread().getName() + " : "+getMemory()); } public void setMemory2(int memory){ System.out.println(Thread.currentThread().getName() +" hi"); System.out.println("동기화블럭 시작할게"); synchronized (this){ this.memory=memory; try { System.out.println(Thread.currentThread().getName()+"잠"); Thread.sleep(5000); } catch (InterruptedException e) { } System.out.println(Thread.currentThread().getName() + " : "+getMemory()); } } //Th1 @Override public void run() { calcul.setMemory(100); try { sleep(2000); } catch (InterruptedException e) { } calcul.prit(); } //Th2 @Override public void run() { calcul.setMemory2(50); }
- 먼저 Th1이 run()실행하는 순간 동기화 method실행 -> sleep
->이 타이밍에 Th2가 동기화 안된 부분 출력 -> 동기화 블럭에서 기다림
- Th1이 작업완료 후 sleep -> th2 동기화된 객체에 접근해서 남은 작업 실행 (객체 동기화)
- Th1이 동기화되지않은 메서드 접근 (ok) -> Th2나머지 작업 완료 후 출력
3.3 wait()과 notify()이용한 스레드 실행제어(동기화 관련)
- 경우의 따라 두 개의 스레드를 교대로 번갈아 가며 실행할 때도 있다.
- 정확한 교대작업이 필요할 시에 자신의 작업이 끝나면 상대방 스레드를 일시 정지 상태에서 풀어주고 자신을 일시 정지로 만들면 된다.
- 이 방법의 핵심은 공유객체에 있다.
- 공유객체가 두 스레드가 작업할 내용을 동기화 메서드로 가지고 있다가 한 스레드 작업이 완료되면, notify메서드를 호출
자신은 두번 작업하지 않도록 wait()한다.
- notify()는 일시정지 중 한개의 스레드 All()은 모든 스레드 깨운다. -> 핵심은 동기화 블럭 내에서만 사용가능
public synchronized void methodA(){ Thread thread =Thread.currentThread(); System.out.println(thread.getName() + "methodA 실행"); notify(); try{ wait(); }catch (InterruptedException e){} } //동기화 메서드를 점유하던 스레드가 일시정지 상태 깨우고, 자신은 wait()상태 // 아직 동기화 메서드가 종료된 것 아니지만 다른 스레드가 객체 동기화 블럭 및 메서드에 접근가능
4. 스레드 안전종료
- run() 중간에 작업을 즉시 중단하고 싶을 때
- 주로 조건을 이용하는 방법과 interrupt()메소드를 사용한다.
4.1 조건이용
public void run(){ while(!stop){ //특정 조건에서 스레드 종료시킴 //스레드가 반복 실행하는 코드 } //스레드 사용리소스 정리 }//스레드 종료
4.2 interrupt()이용
Thread tha = new Thread(); tha.start(); tha.interrupt(); //tha의 run() public void run(){ try{ while(true){ //... Thread.sleep(1); // 일시정지 } }catch(InterruptedException e){ //리소스 정리 } }
* 스레드가 실행대기 혹은 실행중일 때는 interrup()가 작동하지 않는다 따라서 다음과 같은 메서드 활용하자
Thread.interrupted() // 정적메소드 현재 스레드에 작용 objThread.isInterrupted() // 인스턴스 메소드 (특정스레드)
5. 데몬스레드
- 스레드 작업을 돕는 보조적인 역할의 스레드이다. (주 스레드 종료스 데몬 스레드 종료된다)
- 워드프로세서 자동저장, 미디어 플레이어 동영상 및 음악 재생 등등
- 데몬스레드를 만들기 위해서는 주 스레드가 데몬이 될 스레드의 setDemon(true)를 호출하면 된다.
public static void main(String[] args) { AutosaveThread autosaveThread =new AutosaveThread(); autosaveThread.setDaemon(true); autosaveThread.start(); try{ Thread.sleep(3000); }catch (InterruptedException e){} System.out.println("메인 스레드 종료"); } //demon @Override public void run() { while (true){ try { Thread.sleep(1000); } catch (InterruptedException e) { break; } save(); } }
'언어 > JAVA' 카테고리의 다른 글
자바스터디(1) (0) 2023.10.18 자바 네트워크 네트워크 입출력 (1) - TCP (0) 2023.08.22 Java - 일급컬렉션 (0) 2023.07.25 Servlet-JSP MVC07 파일 수정하기 (0) 2023.07.24 Java - File클래스 (0) 2023.07.24