Java - Thread,synchronized

2020. 7. 2. 23:07Java

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package thread_synchronized;
 
public class Ex {
 
    public static void main(String[] args) {
        
        
        
        Account acc=new Account("111-1111-1111""이순신"10000);
        
        
        //3개의 출금 쓰레드에서 1개의 은행계좌에 대한 출금 시도
        WithdrawThread wt1=new WithdrawThread(acc, "인터넷뱅킹"2000);
        WithdrawThread wt2=new WithdrawThread(acc, "모바일뱅킹"2000);
        WithdrawThread wt3=new WithdrawThread(acc, "ATM"2000);
        
        wt1.start();
        wt2.start();
        wt3.start();
        
        
    }
 
}
 
//출금작업을 멀티쓰레딩으로 수행하기 위해 Thread 클래스를 상속받는 서브클래스 정의
class WithdrawThread extends Thread{
    Account obj;//은행계좌를 저장할 변수
    String name;//출금 타입명을 저장할 변수
    int amount;//출금할 금액을 저장할 변수
    public WithdrawThread(Account obj, String name, int amount) {
        super();
        this.obj = obj;
        this.name = name;
        this.amount = amount;
    }
    @Override
    public void run() {
        // 출금작업을 6번 반복
        for(int i=1;i<=6;i++) {
            //전달받은 은행계좌(obj)의 출금 기능(withdraw)를 호출하여 출금금액, 타입명 전달
            //리턴받은 금액이 0보다 작거나 같으면(출금불가능하면) 반복종료
            int result=obj.withdraw(amount, name);
            
            
            //출금된 금액(amount)이 0 이하일때 반복문 종료
            if(result<=0) {
                System.out.println(name+"-출금불가(잔액부족) : "+obj.balance+"원");
                break;
            }
            
            System.out.println(name+"-출금된 금액 : "+amount+" 원(잔고 : "+obj.balance+" 원)");
            
            //출금 속도 조절을 위해 현재작업(쓰레드)을 1초 재움
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
    
    
}
 
 
/*
 * Account 클래스 정의
 * 멤버변수 : 계좌번호(String accountNo),예금주명(String ownerName),현재잔고(int balance)
 * 
 * 메서드
 * 1)생성자-계좌번호, 예금주명, 현재잔고 받아 초기화
 * 2)Getter/Setter
 * 3)입금(deposit)
 * -리턴타입 : 없음
 * -파라미터 : 입금금액(int amount), 입금방식명(String name)
 * -동작 : 현재잔고(balance)에 입금금액(amount) 누적
 *             "입금금액 : XXX원, 입금 후 잔고 : XXX원" 출력
 * 4)출력(withdraw)
 * -리턴타입 : 출금금액
 * -파라미터 : 출금금액(int amount), 출금방식명(String name)
 * -동작 : 현재잔고(balance)보다 출금금액(amount)이 클 경우 메서드 종료(리턴)
 *            -> 출금할 금액 : XXX원, 현재잔고 : XXX원(잔고 부족) 출력
 *            아니면, 현재잔고에서 출금금액을 차감 후
 *            ->출금할 금액 : XXX원 , 출금 후 잔고 : XXX원 출력 후 출금금액 리턴
 * 
 */
 
class Account{
    String accountNo;
    String ownerName;
    int balance;
    public Account(String accountNo, String ownerName, int balance) {
        super();
        this.accountNo = accountNo;
        this.ownerName = ownerName;
        this.balance = balance;
    }
    public String getAccountNo() {
        return accountNo;
    }
    public void setAccountNo(String accountNo) {
        this.accountNo = accountNo;
    }
    public String getOwnerName() {
        return ownerName;
    }
    public void setOwnerName(String ownerName) {
        this.ownerName = ownerName;
    }
    public int getBalance() {
        return balance;
    }
    public void setBalance(int balance) {
        this.balance = balance;
    }
    
    //입금
    public void deposti(int amount,String name) {
        this.balance+=amount;
        System.out.println(name+"-입금금액 : "+amount+" 원, 입금 후 잔고 : "+balance+" 원");
    }
    
    //출금
//    public int withdraw(int amount,String name) {
//        
//        if(balance<amount) {
////            System.out.println(name+"-출금할 금액 : "+amount+" 원, 현재잔고 : "+balance+" 원(잔고 부족)");
//            return 0;
//        }
//            balance-=amount;
////            System.out.println(name+"-출금할 금액 : "+amount+" 원 , 출금 후 잔고 : "+balance+" 원");
//        
//        return amount;
//        
//    }
    
    //동기화 기능 사용을 위해 출금 메서드에 synchronized 키워드 적용
    public synchronized int withdraw(int amount,String name) {
        
        if(balance<amount) {
//            System.out.println(name+"-출금할 금액 : "+amount+" 원, 현재잔고 : "+balance+" 원(잔고 부족)");
            return 0;
        }
            balance-=amount;
//            System.out.println(name+"-출금할 금액 : "+amount+" 원 , 출금 후 잔고 : "+balance+" 원");
        
        return amount;
        
    }
    
    
}
 
 
cs

 

Thread를 사용할 경우 은행의 계좌에 여러 경로로 접근을 하게 될 경우 바로바로 정보의 갱신이 이루어지지 않게 될 경우가 발생할 수 있고 이중 출금이 이루어질 수 있기 때문에 심각한 결함이 생긴다. 그 경우를 방지하고자 생긴 게

synchronized이고 간단하게 접근 제한자 바로 뒤에 써주기만 하면 접근을 할 경우에 신호를 받아 그때만 작동을 하고 다시 멈추고 하는 신호등과 같은 역할을 수행하기 때문에 앞서 말한 심각한 결함이 제거가 된다. 

'Java' 카테고리의 다른 글

Java - JFrame  (0) 2020.07.06
Java - javax.swing, GUI,JFrame  (0) 2020.07.02
Java - Thread  (0) 2020.07.02
Java - throw,throws  (0) 2020.07.02
Java - 예외(Exception),try~catch  (0) 2020.07.02