본문 바로가기
Java/JAVA 문법

자바 기초 배우기 31,32일차 [ Thread 쓰레드 기본개념, Synchronized (동기화작업), wait / Notify ]

by lchit 2020. 1. 5.

Thread

- 스레드란

- 스레드 사용법, 카운트 다운 예제

- 다중 Thread의 공유자원 접근 시

동기화 Synchronized

- 다중 Thread의 wait( ) / Notify( )

프로세스란?

주어진 목적에 따라

어떠한 일이 처리되거나 진행되는 과정

스레드란?

하나의 프로세스 가 실행 중일 때

프로세스를 이루는 단위 실행 요소

다중 스레드?

동시에 복수의 스레드가 동작하는 것

두 개의 스레드가 동시 작동될 때

순차적으로 처리한다면 동기화 처리이며

동시 스레드가 병렬해서 동작한다면

비동기 처리라 한다.

Thread 구현 사용방법 및 카운트 다운 예제

1) extends Thread ( Thread의 상속 생성 )

1. 스레드 클래스를 상속받아 만든다

이렇게 스레드 메서드를 구현할 클래스에

Thread 클래스를 상속받는다.

2. run메서드를 오버 라이딩한다.

run메서드를 오버 라이딩 (재정의) 해주어야 한다

실질적으로 메인에서 스레드를 실행시켰을 때

작동되는 메서드이다

그리고 try-catch 문을 활용하여

스레드 작업의 예외 발생 처리를 해주었는데

필수이다 만약 try-catch가 생략되어있을 시에

오류가 나고 메서드는 완성되지 않는다.

이 run메서드의 경우 반복문을 활용하여

5,4,3,2,1 BAAM!! 을 출력하는 메서드인데

i의 출력과 반복 간에 sleep(1000)이라는 함수가 있는데

이는 Thread 시간 지연이다 i를 한번 출력하면

(1000) = 1초의 지연시간을 가지라는 뜻이다.

5회가 반복되고 for 반복문을 빠져나온다면

BAAM!! 이 출력될 것이다.

3. main에서 객체 생성 후 객체. start(); 를 한다.

메인에서는 스레드 작업을 구현한

클래스를 객체로 만들고 객체. start();

를 해주게 되면 위에서 구현한 스레드 작업인

run();메서드가 실행될 것이다.

결과

그럼 두 개의 객체를 만들어서

동시에 시작시켜보겠다.

동시에 실행되고 있다.

만약 이러한 작업이 하나의

변수를 공유를 하면서 작업을

한다면? 충돌이 발생할 수 도 있다.

잠시 후 이러한 경우의 충돌 상황을

피하기 위하여 동기화하는 것도 살펴보자

2) implements Runnable ( Runnble 인터페이스 구현 생성 )

나머지 부분은 동일한 코드이고

클래스에서 extends Thread로 상속받는 것이 아니라

implements Runnable로

클래스를 만들었다.

그리고 메인에서는

클래스에 대한 객체를 만들고

Thread 객체를 생성하면서 인자로

클래스 객체를 넣어주었다

실제 동작은 Thread의 객체명으로 한다

다중 Thread의 공유자원 접근 시

동기화 (Synchronized)

예를 들어 동기화 작업을

설명하자면 화장실에 변기 한 칸이 있다

똥이 마려운 사람은 두 사람이다

하지만 둘 다 똥이 마렵다고 한들

하나의 변기에선 한 명만이 볼일을 봐야 한다

한 사람이 먼저 들어갔다

이 사람은 다른 사람의 침입을

방지하기 위하여 문을 잠근다 (Lock)

자신의 볼일이 다 끝나면 문을

열고 나온다 (UnLock)

그러면 그다음 사람이 들어가

볼일을 본다.

우리는 대변기라는 자원에 대해

공유를 하지만 우리끼리는

동기화 작업이 돼있어서

한 변기에 같이 볼일을 보는..

그런 일은 발생하지 않을 것이다

동기화가 안 이루어진 사람들끼리

만나면 모를까

그럼 예제로 보자

이 예시는 예제로 별로지만 현실적인? 상황이기에

만들어보았다.

< 예 제 >

일단 동기화가 이뤄지지 않아 참사가 일어나는 상황의 코드다

1. 변기라는 클래스(공유되는 자원)

변기 클래스가 있고

이 클래스의 기능으로는 poo라는

볼일 보는 연출을 해주는 메서드가 있다.

이 부분이 궁금하다면

이건 접근하는 스레드명을 표기해준다

실제 콘솔 출력 시에 실행되는 스레드가 어떤 스레드인지

알기 위해 적어놓은 것이다

2. 사람이라는 스레드

스레드다

매게 변수로 이름과 객체를 받고

이는 여기서 super(name) 즉

상속된 스레드의 명칭이 입력받는

name이 된다

그리고 입력받는 객체를 실제

Toilet에 접근시켜주게 된다.

그리고 스레드 실행 값은 Toilet 클래스의

poo메서드의 호출이다.

3.Main에서의 객체 생성 및 스레드 실행

각각 같은 Toilet에 접근시켜주고(공유)

이름은 서로 다른 lee, kim이다

그리고 이는 human1,2 객체이다

둘 다 동시 실행

자 동시에 실현되선 안될 것이 실행되고 있다

물론 프로그램이니까 상관없긴 한데

실제라고 생각하면 일어나선 안 되는 게 맞다

고로 고쳐주겠다

단 한 부분만 고쳐주면 된다

바로 병렬 작업을 하면 안 되는 메서드에 대해

'synchronized' 키워드를 붙여주는 것이다이다

이 상황에서는 그 메서드는 poo이다

같이 볼일을 보면 안 된다는 것이다.

이게 다다 단순히 스레드가중복 실행되면 안 되는 메서드에는

synchronized를 붙인 것이다.

이렇게 동기화를 시켜주면

이렇게 바뀐다.

 

이제는 두 객체가 하나의

공유된 Toilet으로 접근해 같은 poo를

실행시킨다 한들 동기화가 이뤄진 메서드이기에

동시에 실행하면 안 된다는 것을 안 것이다.

< 예 제2>

1. 잔고가 10만 원이 남은 계좌가 있다.가있다.

2. 계좌에서 두 사람이 서로 다른 ATM기에서

아주 극적으로 동시에 1만 원을 반복하여

인출한다고

3. 은행 시스템에 동기화가 되어있지 않다면

두 사람이 한 계좌에서 동시에 계속해서 뽑는다면

계좌는 10만 원이 남아있을지라도

어쩌다 보면

돈이 인출될 수도 있다

- 동기화 비동기화 두 가지 상황을 보자

1.Bank

은행에는 계좌에 100000만 원 이 있다

출금 기능은

만약 계좌에 10000원 이상이 있다면

1회에 1만 원을 인출한다.

그렇지 않다면 "잔액이 부족하다" 멘트를 출력한다

2.ATM

ATM은 매게 변수 생성자로

이름과 객체를 입력받아

이름은 스레드 이름에 입혀주고

객체는 Bank로 연결해준다

그리고 스레드 실행 작업은

bank의 출금 기능을 6회 반복한다

3.Main

객체를 생성하여

매게 변수를 넣어주고

각각 객체가 동시에

스레드를 실행시킨다

계좌에 10만 원 밖에 없었는데

11만 원을 인출했다 개이득..

else문을 무시하고 1만원을 추가로 얻었다

물론 실행 시 매번 11만 원이 나오는 건 아니다

10만 원 10만원 10만원 제대로 나오다가

어쩌다 보면 저렇게 비동기화로 인해

11만 원이 나올 때도 있는 것이다.

이제 동기화를 시켜주겠다

문제가 있을 수 도있는

기능은 출금 메서드이다

여기에 synchronized 키워드를

붙이는 것이다.

이렇게 동기화 후에는

1번 객체가 먼저 반복문을 끝내고 난 뒤에

2번 객체가 Bank에 접근해서 작업을 하기에

else문을 얼렁뚱땅 넘어갈 일이 없다

지금까지 두 가지 예제로 synchronized를 보았다

다중 Thread의 wait( ) / Notify( )

똥쟁이와 ATM 사기범 들의 예제 동기화 말고도

이러한 충돌을 방지할 수 있는

wait()와 Notify() 가있다

wait() 말 그대로 기다려!이고

Notify() 이제 움직여!라고 알리는 것이다

바로 예제 봅시다

스레드 A와 스레드 B가 일을 합니다

이것은 두 스레드가 번갈아가며 일을 하고 있는 장면입니다

어떻게 했을까요?

스레드가 협업을 한다라..

notify와 wait로 가능합니다

코드를 봐보겠습니다

1. 공유 클래스

여기가 스레드 두 마리가 같이 일을 하게 될 공간입니다

Work A 메서드와 Work B메서드가 있네요

synchronized를 보니 동기화 작업이 이뤄지는

메서드임에는 짐작이 가고

notify();와 wait(); 가 보입니다

여기서 이 notify(); 와 wait();의 기능은

notify(); >> 일시정지돼있는 Thread B를

실행 대기상태로 만들어 놓는다!

wait(); >> Thread A가 일시 정지 상태로 변화함

이것으로 동기화된 두 메서드 간에 스레드 실행 시

서로 교차? 하며 협업을 진행할 수 있게 됩니다.

2.Thread클래스, run() 메서드 재정의 부

 

Thread A

Thread B

두 클래스 모드 WorkZone이라는 공유 클래스에서

작동되고,

매게 변수로 생성자로서 문자열과 객체를 받아오며

5회 동안 스레드 자기 자신의 이름을 출력하며

WorkZone이라는 클래스에

WorkA메서드 와 WorkB메서드를

각각 실행하도록 하는 run() 메서드를 가지고 있네요.

3. 마지막으로 Main 부

하나의 공유될 객체를 만들고

그 객체를 각각 WorkerA와 WorkerB에게

스레드 A 스레드 B라는 이름과 함께 쥐어주고

스레드를 실행시켰네요

이렇게 해서 실행결과가

두메 서드 간에 각각 스레드들이

서로 교차하며 멈추었다가 다른 스레드를 실행하고

또 그 스레드가 멈추었다 다시 다른 스레드가 실행되고

의 반복 과정을 볼 수 있었습니다