スレッド同期の必要性


1、口座類
package com.ljb.app.synchronize;
/**
 *  ( )
 * @author LJB
 * @version 2015 3 10 
 */
public class Account {
 //  
 private int balance = 500;
 
 //  
 public int getBalance() {
  return balance;
 }
 //  ( < 0, >)
 public void withdraw (int amount) {
  balance = balance - amount;
 }
}

2、引き出しスレッド(同じ口座を持つ)
 package com.ljb.app.synchronize;
/**
 *  ( )
 * @author LJB
 * @version 2015 3 10 
 */
public class WithdrawThread implements Runnable{
 /*
  *   
  */
 private Account account = new Account();
 
 /*
  *   、 (non-Javadoc)
  * @see java.lang.Runnable#run()
  */
 public void run () {
  for (int i = 0 ; i < 5 ; i++) {
   //  
   makeWithdraw(100);
   
   //  
   if (account.getBalance() < 0) {
    System.out.println(" !");
   }
  } 
 }
 
 /*
  *   ( )
  */
 private void makeWithdraw (int amount) {
  if (account.getBalance() >= amount) {
   System.out.println(Thread.currentThread().getName() + " 。");
   
   try {
    Thread.sleep(500);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   
   // 0.5 
   account.withdraw(amount);
   System.out.println(Thread.currentThread().getName() + " 。");
  } else {
   System.out.println(" " 
        + Thread.currentThread().getName()
        + " , " + account.getBalance());
  }
 }
}

3、テストクラス
 package com.ljb.app.synchronize;
/**
 *  2 
 * @author LJB
 * @version 2015 3 10 
 */
public class TestWithdraw {
 /**
  * @param args
  */
 public static void main(String[] args) {
  //  Runnable 
  WithdrawThread withdraw = new WithdrawThread();
  
  //  2 
  Thread husband = new Thread(withdraw);
  Thread wife = new Thread(withdraw);
  
  husband.setName(" ");
  wife.setName(" ");
  
  husband.start();
  wife.start();
 }
}

実行結果:
夫は金を引き出すつもりだ.妻は金を引き出すつもりだ.妻は引き出しを済ませた.妻は金を引き出すつもりだ.夫は引き出しを済ませた.夫は金を引き出すつもりだ.妻は引き出しを済ませた.妻は金を引き出すつもりだ.夫は引き出しを済ませた.夫は金を引き出すつもりだ.妻は引き出しを済ませた.夫は引き出しを済ませた.妻は金を引き出すつもりだ.夫は金を引き出すつもりだ.夫は引き出しを済ませた.口座が貸越した!妻は引き出しを済ませた.口座が貸越した!残高は妻の引き出しを支払うのに十分ではありません.残高は-100口座の貸越です.残高は夫の引き出しを支払うのに十分ではありません.残高は-100口座の貸越です.4、同期方法
/*
  *   ( )
  */
 private synchronized void makeWithdraw (int amount) {
  if (account.getBalance() >= amount) {
   System.out.println(Thread.currentThread().getName() + " 。");
   
   try {
    Thread.sleep(500);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   
   // 0.5 
   account.withdraw(amount);
   System.out.println(Thread.currentThread().getName() + " 。");
  } else {
   System.out.println(" " 
        + Thread.currentThread().getName()
        + " , " + account.getBalance());
  }
 }

実行結果:
夫は金を引き出すつもりだ.夫は引き出しを済ませた.妻は金を引き出すつもりだ.妻は引き出しを済ませた.妻は金を引き出すつもりだ.妻は引き出しを済ませた.妻は金を引き出すつもりだ.妻は引き出しを済ませた.夫は金を引き出すつもりだ.夫は引き出しを済ませた.残高は夫の引き出しを支払うのに十分ではなく、残高は0残高で夫の引き出しを支払うのに十分ではなく、残高は0残高で夫の引き出しを支払うのに十分ではなく、残高は0残高で妻の引き出しを支払うのに十分ではなく、残高は0残高で妻の引き出しを支払うのに十分ではなく、残高は0
5、同期コードブロック(同期方法より強い)
/*
  *   ( )
  */
 private void makeWithdraw (int amount) {
  synchronized (account) {
   if (account.getBalance() >= amount) {
    System.out.println(Thread.currentThread().getName() + " 。");
    
    try {
     Thread.sleep(500);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    
    // 0.5 
    account.withdraw(amount);
    System.out.println(Thread.currentThread().getName() + " 。");
   } else {
    System.out.println(" " 
         + Thread.currentThread().getName()
         + " , " + account.getBalance());
   }
  }
 }