본문

160103P(일)

Java - Chapter 18 멀티스레드 프로그래밍

 

스레드(thread)

한 가닥 실

명령문이 실행되는 순서를 따라가다 보면 길게 연결된 한 가닥 실과 같은 흐름이 있다.

 

1. java.lang.Thread

class MultithreadExample1 {

public static void main(String args[]) {

Thread thread = new DigitTread();

thread.start();

 

...

 

try {

Thread.sleep(1000);

} catch(InterruptedException e) {

System.out.println(e.getMessage());

}

}

}

 

class DigitThread extends Thread {

public void run() {

...

 

try {

Thread.sleep(1000);

} catch(InterruptedException e) {

System.out.println(e.getMessage());

}

}

}

 

2. java.lang.Runnable

class MulithreadExample3 {

public static void main(String args[]) {

Thread thread = new Thread(new SmallLetters());

thread.start();

 

...

}

}

 

class SmallLetters implements Runnable {

public void run() {

...

}

}

 

스레드간의 커뮤니케이션

공유메모리의 데이터를 두 개 이상의 스레드가 서로 공유 할 때

 

class SharedArea {

double result;

}

 

class MultithreadExample4 {

public static void main(String args[]) {

CalcThread thread1 = new CalcThread();

PrintThread thread2 = new PrintThread();

 

SharedArea obj = new SharedArea();

 

thread1.sharedArea = obj;

thread2.sharedArea = obj;

 

thread1.start();

thread2.start();

}

}

 

class CalcThread extends Thread {

SharedArea = sharedArea;

 

public void run() {

...

 

sharedArea.result = total * 4;

}

}

 

class PrintThread extends Thread {

SharedArea sharedArea;

 

public void run() {

...

System.out.println(sharedArea.result);

}

}

 

스레드간의 문제 - resutl에 데이터를 쓰기도 전에 thread2가 출력해버린다.

1. SharedArea 클래스에 데이터 유무를 표시하는 필드를 추가

 

class SharedArea {

double result;

boolean isReady;

}

 

class MultithreadExample4 {

public static void main(String args[]) {

CalcThread thread1 = new CalcThread();

PrintThread thread2 = new PrintThread();

 

SharedArea obj = new SharedArea();

 

thread1.sharedArea = obj;

thread2.sharedArea = obj;

 

thread1.start();

thread2.start();

}

}

 

class CalcThread extends Thread {

SharedArea = sharedArea;

 

public void run() {

...

 

sharedArea.result = total * 4;

sharedArea.isReady = true;

}

}

 

class PrintThread extends Thread {

SharedArea sharedArea;

 

public void run() {

...

 

while(sharedArea.isReady != true) {

continue;

}

 

System.out.println(sharedArea.result);

}

}

∴ 굉장히 비효율적인 방법이다.

 

어떤 자바 컴파일러는 프로그램 성능 향상을 위해서 변수의 값을 바꾸지 않고 반복해서 체크할 경우에는 그 값을 한번 가져다 놓고 여러 번 사용하도록 최적화 한다. 따라서 volatile(휘발성)을 키워드를 붙이면 된다.

 

class SharedArea {

double result;

volatile boolean isReady;

}

 

2. Thread.sleep() 메소드를 사용해서 필드값을 쓰는 시간을 벌어주면 된다.

∴ 더 좋은 방법은 ciritical section 동기화!

 

3. critical section synchronization

critical section이 실행되는 동안 다른 스레드가 공유 데이터를 사용할 수 없도록 만드는 것

 

class SharedArea {

Account account1;

Account account2;

}

 

class MultithreadExample5 {

public static void main(String args[]) {

SharedArea area = new SharedArea();

 

...

}

}

 

class TransferThread extends Thread {

SharedArea sharedArea;

TransferThread(SharedArea area) {

sharedArea = area;

}

 

public void run() {

...

 

synchronized(sharedArea) {

sharedArea.account1.withdraw(100000);

sharedArea.account2.deposit(100000);

}

}

}

 

class PrintThread extends Thread {

SharedArea sharedArea;

PrintThread(SharedArea area) {

sharedArea = area;

}

 

public void run() {

...

 

synchronized(sharedArea) {

int sum = sharedArea.account1.balance + sharedArea.account2.balance;

}

 

try {

Thread.sleep(1);

} catch(InterruptedException e) {

System.out.println(e.getMessage());

}

}

}

 

동기화 영역 지정

synchronized (공유_객체) {

ciritical section

}

 

동기화 메소드

1.

class SharedArea {

Account account1;

Account account2;

 

void transfer(int amount) {

synchronized(this) {

...

}

}

}

 

2.

class SharedArea {

Account account1;

Account account2;

 

synchronized void transfer(int amount) {

...

}

}

 

스레드간의 신호 전송

반드시 동기화블록이나 동기화 메소드 내에서 사용해야 한다.

 

notify

다른 스레드에게 신호를 보내는 메소드

 

wait

notify 신호가 오기를 기다리는 메소드

 

class CalcThread extends Thread {

...

public void run() {

synchronized(obj) {

obj.notify();

}

}

}

 

class PrintThread extends Thread {

...

public void run() {

synchronized(obj) {

obj.wait();

}

}

}

 

한꺼번에 신호 보내기

class CalcThread extends Thread {

...

public void run() {

synchronized(obj) {

obj.notifyAll();

}

}

}

 

스레드의 상태

New Thread(run 메소드에 진입 전) -> Runnable or Not Runnable -> Dead Thread

 

Not Runnable

wait나 sleep 등 실행 불가능 상태

 

스레드의 상태를 알아내는 메소드

Thread.State state = thread.getState();

 

State

열거타입

 

NEW - 실행되기 전

RUNNABLE - 실행 가능 상태

WAITING - wait 메소드 호출 상태

TIME_WAITING - sleep 메소드 호출 상태

BLOCKED - synchronized 끝나기를 기다리는 상태

TERMINATED - 실행 마친 상태

 

class MonitorThread extends Thread {

Thread thread;

MonitorThread(Thread thread) {

this.thread = thread;

}

 

public void run() {

while(true) {

Thread.State state = thread.getState();

 

if(state == Thread.State.TERMINATED) {

break;

}

 

try {

Thread.sleep(2000);

} catch(InterruptedException e) {

e.printStackTrace();

}

}

}

}

 


 

Thread 고급

 

뮤텍스와 세마포어

http://topnanis.tistory.com/195

http://crack-tech-interview.com/2014/01/26/semaphore-%EC%99%80-mutex-mutual-exclusion/comment-page-1/

 

뮤텍스(MUTual EXclution : MUTEX)

synchronized로 뮤텍스 락(mutex-lock)를 해줌으로써 구현한다.

 

세마포어(Semaphore)

1. wait, notifyAll로 구현

2. java.util.concurrent.Semaphore의 acquire(), release()로 구현

 

http://gladtosee.tistory.com/191

http://imdsoho.tistory.com/entry/Semaphore-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%98%88%EC%A0%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8

 

∴ JAVA 디자인 패턴 책을 하나 봐야할 것 같다.

'Programming > Java' 카테고리의 다른 글

160117P(일)  (0) 2016.01.17
160109P(토)  (0) 2016.01.10
160108P(금)  (0) 2016.01.09
160107P(목)  (0) 2016.01.07
151220P(일)  (0) 2015.12.20

공유

댓글