2014-01-08 3 views
2

나는 계정 모델을 가지고 있으며이를 동기식으로 철회하고 싶습니다. 그러나 메서드를 동기화하고 run 메서드에서 호출 한 후에도 출력 순서대로 문제가 여전히 남아 있습니다. 여기 내 코드가있다. 나는 정말로 그 문제가 뭔지 모른다.run 메서드에서 synchronized 메서드 호출

public class Account { 
private double balance; 
public Account(double balance) { 
    this.balance = balance; 
} 
public double getBalance() { 
    return balance; 
} 
public void setBalance(double balance) { 
    this.balance = balance; 
} 
} 


public class WithdrawThread implements Runnable { 
private double amount; 
private Account account; 

public WithdrawThread(Account account, double amount) { 
    this.account = account; 
    this.amount = amount; 
} 

public synchronized void withdraw(double amount) { 

    double bal = account.getBalance(); 
    if (amount > account.getBalance()) 
     throw new IllegalArgumentException("wrong amount"); 
    bal -= amount; 
    account.setBalance(bal); 
    System.out.println(amount + " withdraw in thread number" +  Thread.currentThread().getId() + " balance is " + bal); 
} 

public void run() { 
    withdraw(amount); 
} 

} 소티 Delimanolis 의해 명시된 바와

public class MainThread { 
public static void main(String[] args) { 
    Account account = new Account(200); 
    new Thread(new WithdrawThread(account, 40)).start(); 
    new Thread(new WithdrawThread(account, 10)).start(); 
    new Thread(new WithdrawThread(account, 10)).start(); 
    new Thread(new WithdrawThread(account, 20)).start(); 
    new Thread(new WithdrawThread(account, 30)).start(); 
    new Thread(new WithdrawThread(account, 10)).start(); 
    new Thread(new WithdrawThread(account, 40)).start(); 
} 
} 

sample output

+6

메소드 정의에서'synchronized' 키워드를 사용하면 자바가 현재 객체 ('this')와 동기화됩니다. 너는 7 개의 다른 물건을 가지고있다. 그들은 전혀 조정되지 않습니다. –

+1

+1 to Sotorios. withdraw()는 Account의 메소드 여야하며,이 메소드는 동기화되어야합니다. 물론 다른 것들 (setBalance(), getBalance())도 모두 공유 된 가변 균형에 액세스하기 때문에 동기화되어야합니다. –

+0

그러나 여러 가지 다른 방법이있을 수 있으므로이 메서드를 Account 클래스로 옮기고 싶지 않습니다. 모든 물체를 어떻게 조정할 수 있습니까? – sina

답변

3

이 동기화 방법은 WithdrawThread의 인스턴스가에서 호출 대상으로부터 자물쇠를 사용한다. 계정을 잠 그려면 ...

계정 방법을 철회하거나 동기화 된 블록을 사용하십시오.

public void withdraw(double amount) { 
    double bal; 
    synchronized(account) { 
     bal = account.getBalance(); 
     if (amount > account.getBalance()) 
      throw new IllegalArgumentException("wrong amount"); 
     bal -= amount; 
     account.setBalance(bal); 
    } 
    System.out.println(amount + " withdraw in thread number" + Thread.currentThread().getId() + " balance is " + bal); 
} 
2

synchronize 때 특정 개체를 동기화합니다. 그런 다음 다른 사용자가 완료 할 때까지 해당 개체를 동기화하지 못하게합니다.

개체를 지정하지 않으면 this에서 동기화됩니다.

그래서 각 스레드가 동기화됩니다.

대신 메서드 내에서 동기화 된 블록을 사용하고 수정되는 Account과 같은 공통 개체에 동기화해야합니다.

public void withdraw(double amount) { 
    synchronized (account) { 
     double bal = account.getBalance(); 
     if (amount > account.getBalance()) 
      throw new IllegalArgumentException("wrong amount"); 
     bal -= amount; 
     account.setBalance(bal); 
     System.out.println(amount + " withdraw in thread number" +  Thread.currentThread().getId() + " balance is " + bal); 
    } 
} 
관련 문제