quilt code

[고급자바] Thread(5) 본문

daily/고급자바

[고급자바] Thread(5)

김뱅쇼 2023. 2. 10. 18:45

1. 스레드에서 데이터를 공통으로 사용하는 방법


스레드에서 데이터를 공통으로 사용하는 방법

1. 공통으로 사용할 데이터를 클래스로 정의한다.
2. 공통으로 사용할 클래스의 인스턴스를 만든다.
3. 이 인스턴스를 각각의 스레드에 넘겨준다.
4. 각각의 스레드는 이 인스턴스의 참조값을 지정한 변수를 이용하여 공통 데이터를 사용한다.
예) 원주율을 계산하는 스레드가 있고, 계산된 원주율을 출력하는 스레드가 있다.
      원주율을 계산한 후 이 값을 출력하는 프로그램을 작성하시오.
      (이 때 원주율을 저장하는 객체가 필요하다)
1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
        
        ShareData sd = new ShareData();
        
        Thread th1 = new CalcPIThread(sd);
        Thread th2 = new PrintPIThread(sd);
        
        th1.start();
        th2.start();
        
        
    }
cs

 

2. 원주율

volatile  선언된 변수를 컴파일러의 최적화 대상에서 제외시킨다. 즉, 값이 변경되는 즉시 변수에 적용시킨다.
멀티스레드 환경에서 하나의 변수가 완벽하게 한번에 작동하도록 보장하는 키워드(일종의 동기화)

 

1) 원주율을 관리하는 클래스 (공통으로 사용할 클래스

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class ShareData {
    private double result;  // 원주율이 저장될 변수
    
    volatile private boolean isOK;   // 원주율 계산이 완료되었는지를 확인하기 위한 변수
    
    public double getResult() {
        return result;
    }
    public void setResult(double result) {
        this.result = result;
    }
    public boolean isOK() {
        return isOK;
    }
    public void setOK(boolean isOK) {
        this.isOK = isOK;
    }    
}
 
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
class CalcPIThread extends Thread {
    private ShareData sd;
 
    public CalcPIThread(ShareData sd) {
        this.sd = sd;
    }
    
    @Override
    public void run() {
    /*
     *   원주율 = (1/1 - 1/3 + 1/5 - 1/7 + 1/9 ....) * 4;
     *            1  -  3  +  5  -  7  +  9   => 분모
     *            0     1     2     3     4   => 2로 나눈 몫 
     */
        double sum = 0.0;
        
        for(int i=1; i<=15000000; i+=2) {
            if( ((i/2) % 2== 0) {    // 2로 나눈 몫이 짝수이면... + 
                sum += (1.0/i);
            } else {
                sum -= (1.0/i); 
            }
        }
        
        sd.setResult(sum * 4);   // 계산된 원주율 공통객체에 저장하기
        sd.setOK(true);          // 계산이 완료되었음을 저장함.
        
        
        
    }
    
}
cs

 

3) 계산된 원주율을 출력하는 스레드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class PrintPIThread extends Thread {
    
    private ShareData sd;
    
    public PrintPIThread(ShareData sd) {
        this.sd = sd;
    }
    
    @Override
    public void run() {
        
        while(true) {
            if(sd.isOK()) {
                break;
            }
        }
        
        System.out.println();
        System.out.println("계산된 원주율 : " + sd.getResult());
        System.out.println("       PI : " + Math.PI);
    }
        
}
cs

 

 

3.  SyncThread

1
2
3
4
5
6
7
8
9
10
11
12
public class T15SyncThreadTest {
    public static void main(String[] args) {
        ShareObject sObj = new ShareObject();
        
        Thread th1 = new WorkThread("1번 스레드", sObj);
        Thread th2 = new WorkThread("2번 스레드", sObj);
        
        th1.start();
        th2.start();
    }
 
}
cs

 

1) 공통으로 사용할 클래스

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class ShareObject {
    private int sum = 0;
    
    // 동기화 하는 방법1 : 메소드 자체에 동기화 설정하기 
    // public synchronized void add() {
    public synchronized void add() {
        for(int i= 0; i<1000000000; i++) {
            
    }
        // 동기화 하는 방법2 : 동기화 블럭으로 설정하기
        // mutex : Mutual exclusion Object (상호 배제: 동시 접근 차단)
        
        synchronized (this) {
            int n = sum;
            n += 10;
            sum = n;
            
            System.out.println(Thread.currentThread().getName() + " 합계: " + sum);
            
    }
 }
}
cs

 

2) 작업을 수행하는 스레드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class WorkThread extends Thread {
    private ShareObject sObj;
 
    public WorkThread(String name, ShareObject sObj) {
        super(name);
        this.sObj = sObj;
    }
     @Override
    public void run() {
        for(int i=1; i<=10; i++) {
            synchronized (sObj) {
                sObj.add();
        
            }
        }
    }    
    
}
cs

 

3) 은행의 입출금을 스레드로 처리하는 예제 (synchronized를 이용한 동기화 처리)

 

① 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class T16SyncAccountTest {
    
    public static void main(String[] args) {
        
        SyncAccount sAcc = new SyncAccount();
        
        sAcc.deposit(10000);
        
        Thread th1 = new BankThread(sAcc);
        Thread th2 = new BankThread(sAcc);
        
        th1.start();
        th2.start();
        
    }
 
}
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
class SyncAccount {
    
    private int balance;  //잔액
    
    public int getBalance() {
        return balance;
    }
    
    // 입금 처리를 수행하는 메소드
    public void deposit(int money) {
        balance += money;
    }
    
    // 출금을 처리하는 메소드(출금 성공: true, 출금 실패: false반환)
    // 동기화 영역에서 호출하는 메소드로 동기화 처리를 해주어야 한다.
    synchronized public boolean withdraw(int money) {
        
        if(balance >= money) {
            for(int i=1; i<=1000000000; i++) {  // 시간 때우기 용
        }
        balance -= money;
        
        System.out.println("메소드 안에서 balance = " + getBalance());
        return true;
        
       }  else {
           return false;
       }
 
    }
}
cs

 

③ 은행 업무를 처리하는 스레드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class BankThread extends Thread {
    private SyncAccount sAcc;
    
    public BankThread(SyncAccount sAcc) {
        this.sAcc = sAcc;
    }
    
    @Override
    public void run() {
        boolean result = sAcc.withdraw(6000);  // 6000원 인출
        System.out.println("스레드 안에서 result = " + result + ", balance = " + sAcc.getBalance());
    }
        
}
cs

'daily > 고급자바' 카테고리의 다른 글

[고급자바] IO (1)  (0) 2023.02.13
[고급자바] Thread(6)  (0) 2023.02.13
[고급자바] Thread (4)  (0) 2023.02.10
[고급자바] 컴퓨터와 가위바위보 프로그램  (0) 2023.02.07
[고급자바] Thread(3)  (0) 2023.02.07