본문 바로가기
Java/study

멀티스레드 Synchronized Account Testing

by avvin 2019. 4. 16.

https://www.w3resource.com/java-tutorial/java-code-synchronization.php



Account : 공유하는 계좌 클래스


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package synchronization;
 
public class Account {
 
    private int balance = 50;
 
    public int getBalance() {
        // TODO Auto-generated method stub
        return this.balance;
    }
 
    public void withdraw(int amount) {
        // TODO Auto-generated method stub
        this.balance -= amount;
    }
 
}
 
cs




Runnable 인터페이스의 구현객체 AccountTesting과 SynchronizedAccountTesting 구현하기.

AccountTesting의 makewithdrawal 메서드는 동기화되지 않은 메서드이고

SynchronizedAccountTesting의 makewithdrawal 메서드는 synchronized 키워드가 붙은 동기화 메서드



각 구현클래스에서 Account 타입의 공유객체를 생성하고


makewithdrawal 메서드에서 


this.acct.withdraw(amount);


공유객체의 함수를 호출하여 balance값을 변경해주고 인출 완료 메시지를 프린트


start() 로 실행되는 run()메서드에서 makewithdrawal 메서드를 호출


사람 이름의 스레드를 두개 만들고 스레드를 실행.






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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package synchronization;
 
public class AccountTesting implements Runnable {
    private Account acct = new Account();
 
    public static void main(String[] args) {
 
        AccountTesting r = new AccountTesting();
        // Runnable 인터페이스 구현 클래스 객체를 매개값으로 직접 Thread 객체 생성
 
        Thread one = new Thread(r);
        Thread two = new Thread(r);
        one.setName("Ranjeet");
        two.setName("Reema");
        one.start();
        two.start();
    }
 
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i = 0; i < 5; i++) {
 
            this.makeWithdrawal(10); // 동기화메서드 호출
            if (this.acct.getBalance() < 0) {
 
                System.out.println("account is overdrawn!");
            }
        }
 
    }
 
    // 동기화 메서드
    private void makeWithdrawal(int amount) {
        // TODO Auto-generated method stub
        if (this.acct.getBalance() >= amount) {
 
            System.out.println(Thread.currentThread().getName() + " is going to withdraw");
            // [현재 스레드 이름] is going to withdraw
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
 
                System.out.println(e.getMessage());
            }
            this.acct.withdraw(amount);
            System.out.println(Thread.currentThread().getName() + " complete the withdrawal");
        } else {
            System.out.println("Not enough in account for " + Thread.currentThread().getName() + "to withdraw "
                    + this.acct.getBalance());
 
        }
 
    }
}
 
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package synchronization;
 
public class SynchronizedAccountTesting implements Runnable {
 
    private Account acct = new Account();
 
    public static void main(String[] args) {
 
        SynchronizedAccountTesting r = new SynchronizedAccountTesting();
        // Runnable 인터페이스 구현 클래스 객체를 매개값으로 직접 Thread 객체 생성
 
        Thread one = new Thread(r);
        Thread two = new Thread(r);
        one.setName("Ranjeet");
        two.setName("Reema");
        one.start();
        two.start();
    }
 
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i = 0; i < 3; i++) {
 
            this.makeWithdrawal(10); // 동기화메서드 호출
            if (this.acct.getBalance() < 0) {
 
                System.out.println("account is overdrawn!");
            }
        }
 
    }
 
    // 동기화 메서드
    private synchronized void makeWithdrawal(int amount) {
        // TODO Auto-generated method stub
        if (this.acct.getBalance() >= amount) {
 
            System.out.println(Thread.currentThread().getName() + " is going to withdraw");
            // [현재 스레드 이름] is going to withdraw
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
 
                System.out.println(e.getMessage());
            }
            this.acct.withdraw(amount);
            System.out.println(Thread.currentThread().getName() + " complete the withdrawal");
        } else {
            System.out.println("Not enough in account for " + Thread.currentThread().getName() + "to withdraw "
                    + this.acct.getBalance());
 
        }
 
    }
 
}
 
cs



AccountTesting타입을 매개값으로 받은 스레드는  동기화되지 않은 메서드를 사용하기때문에 스레드끼리 불규칙적으로 동시 실행된다.


SynchronizedAccountTesting타입을 매개값으로 받은 스레드는  동기화된 메서드를 사용하기때문에 

한 스레드가 메서드를 사용하고 있을때 다른 (동기화 메서드를 사용할)스레드는 실행되지 않는다.


인출 메서드를 동기화하지 않으면 두 사람이 같은 계좌를 공유하여 동시에 인출하다가 잔액이 마이너스로 뜨는 오류가 생길 수 있다.

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

람다식(Lambda Expression)  (0) 2019.04.18
제네릭(Generic)  (0) 2019.04.17
멀티스레드  (0) 2019.04.16
Java 자주쓰는 단축키 모음  (0) 2019.04.15
예외 처리  (0) 2019.04.11