[Java 15-1 AccountUserApp] 다중스레드 프로그램의 문제점 및 해결법

임승현·2022년 10월 19일

Java

목록 보기
66/126

🐧다중스레드 프로그램의 문제점

→ 동일한 다수의 스레드가 run() 메소드의 명령을 동시에 실행할 경우 메소드를 호출하여 필드값(공유)을 변경하면 잘못된 결과 발생 가능

🐧해결법) 스레드를 동기화를 이용하여 스레드에 대한 메소드 호출 제어

◎스레드 동기화(Thread Synchronized) : 스레드에 의해 메소드 호출시 메소드의 모든 명령을 모두 처리하기 전까지 다른 스레드의 메소드 실행을 방지하기 위한 기능
→ 스레드를 일시 중지하여 명령이 실행되지 않도록 락(Lock) 기능 제공

🐧스레드 동기화 처리 방법

  1. synchronized 키워드를 사용하여 메소드 선언 - 동기화 메소드(Synchronized Method)
    형식) 접근제한자 synchronized 반환형 메소드명(자료형 매개변수명,...) {}
  2. synchronized 키워드로 블럭을 설정하여 메소드 호출
    형식) synchronized(객체) { 객체,메소드명(값,...);...}
    → 객체로 호출되는 모든 메소드는 동기화 처리되어 실행
package xyz.itwill.thread;

public class AccountUserApp {
	public static void main(String[] args) {
		//은행계좌정보를 생성하여 저장
		Account account=new Account(10000);
		
		/*
		//단일 스레드(main)를 이용하여 은행계좌 사용자를 생성하여 입금 처리
		AccountUser[] users=new AccountUser[3];
		//모든 사용자가 동일한 계좌 사용
		users[0]=new AccountUser(account, "홍길동");
		users[1]=new AccountUser(account, "임꺽정");
		users[2]=new AccountUser(account, "전우치");
		
		for(AccountUser user:users) {
			user.getAccount().deposit(user.getUserName(), 5000);
		}
		*/
		
		//다중 스레드(main)를 이용하여 은행계좌 사용자를 생성하여 입금(출금) 처리
		new AccountUser(account, "홍길동").start();
		new AccountUser(account, "임꺽정").start();
		new AccountUser(account, "전우치").start();
	}
}
package xyz.itwill.thread;

//은행계좌정보(잔액)를 저장하기 위한 클래스
public class Account {
	private int balance;
	
	public Account() {
		// TODO Auto-generated constructor stub
	}

	public Account(int balance) {
		super();
		this.balance = balance;
	}

	public int getBalance() {
		return balance;
	}

	public void setBalance(int balance) {
		this.balance = balance;
	}
	
	//입금 처리 메소드 - 매개변수로 입금자와 입금액을 전달받아 처리
	//public void deposit(String name, int amount) {
	public synchronized void deposit(String name, int amount) {
		balance+=amount;
		System.out.println("[입금]"+name+"님이 "+amount+"원을 입금하여 
        잔액은 "+balance+"원입니다.");
	}
	
	//출금 처리 메소드 - 매개변수로 출금자와 출금액을 전달받아 처리
	//public void withDraw(String name, int amount) {
	public synchronized void withDraw(String name, int amount) {
		if(balance<amount) {
			System.out.println("[에러]"+name+"님, 잔액이 "+balance+"원 
            남아 "+amount+"원을 출금할 수 없습니다.");
			return;
		}
		
		balance-=amount;
		System.out.println("[출금]"+name+"님이 "+amount+"원을 출금하여 
        잔액은 "+balance+"원입니다.");
	}
	
}
package xyz.itwill.thread;

//은행계좌 사용자정보(은행계좌정보, 사용자명)를 저장하기 위한 클래스
public class AccountUser extends Thread {
	private Account account;//은행계좌정보 - 포함관계
	private String userName;
	
	public AccountUser() {
		// TODO Auto-generated constructor stub
	}

	public AccountUser(Account account, String userName) {
		super();
		this.account = account;
		this.userName = userName;
	}

	public Account getAccount() {
		return account;
	}

	public void setAccount(Account account) {
		this.account = account;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		// 프로그램 개발자에 의해 생성된 새로운 스레드가 run() 메소드의 명령 실행
		// 은행계좌 사용자에 의한 입금 처리 메소드 호출
		//account.deposit(userName, 5000);
		
		synchronized (account) {
			
		account.withDraw(userName, 5000);
		}
	}
}

0개의 댓글