线程同步案例:
1 package com.iotek.synchronizedtest; 2 3 public class BankDemo { 4 5 /** 线程同步案例 6 * 对于线程同步,在java代码中需要完成2个操作: 7 * (1)把竞争访问的资源标识为private 8 * (2)同步哪些访问资源的代码,使用synchronized关键字来修饰方法或代码块 9 * 当synchronized方法执行完成或发生异常时,会自动释放锁 10 * 案例:某银行卡账号上有500元现金,一个人拿着存折去柜台取钱, 11 * 同时另一个人拿着卡去ATM上取钱,各自取400元。现要求取钱的过程中不能 12 * 出现资源竞争:比如400元被取出2次,银行的账目不能小于0等 13 * 14 * @param args 15 */ 16 public static void main(String[] args) { 17 Bank bank = new Bank(); 18 BankTherad p1 = new BankTherad(bank); 19 p1.start(); // 模拟柜台取钱 20 BankTherad p2 = new BankTherad(bank); 21 p2.start(); // 模拟ATM取钱,与模拟柜台取钱,是2个线程,竞争同一个资源:账户的余额 22 23 } 24 25 } 26 27 class BankTherad extends Thread { 28 private Bank bank = null; // 声明一个银行对象的引用 29 30 public BankTherad(Bank bank) { 31 this.bank = bank; 32 } 33 34 public void run() { 35 System.out.println("取钱:" + bank.getMoney(400)); 36 } 37 } 38 39 class Bank { 40 private int money = 500; // 银行账户里的钱是一种竞争资源,设置为私有属性 41 private Object obj = new Object(); 42 43 /* 44 * synchronized关键字声明当前方法是同步方法,当一个线程去调用同步方法时, 45 * 这个线程就获取了当前对象的锁.获取当前对象锁的线程就去执行同步方法里的语句 46 * 其他的线程当调用同步方法时,只能等待,因为无法获取对象的锁,这个锁已被第一个 线程持有, 只有第一个线程释放对象的锁,方可进入 47 * 同步方法的作用就是确保方法里的代码同时只能有一个线程来访问,当同步方法运行完毕, 其他线程才能访问 48 */ 49 /* 50 * public synchronized int getMoney(int number) { if (number < 0) { return 51 * -1; } else if (money < 0) { return -2; } else if (number - money > 0) { 52 * return -3; // 取钱数目大于银行卡账户余额 } else { // 除此之外,都是正常状态 try { 53 * Thread.sleep(1000); } catch (InterruptedException e) { 54 * e.printStackTrace(); } // 休眠1秒钟,模拟取钱的时间 money -= number; // 取钱后的账户余额 55 * System.out.println("余额:" + money); } return number; } 56 */ 57 // 取钱的方法,返回取钱的数目 58 public int getMoney(int number) { 59 //使用同步代码块: synchronized (this) { } this代表获取的是当前对象的锁 60 synchronized (obj) { //此处获取任何对象的锁都是可以的 61 //this代表当前对象 62 if (number < 0) {//取钱数目不能小于0 63 return -1; 64 } else if (money < 0) {//银行账户余额不能小于0 65 return -2; 66 } else if (number - money > 0) { 67 return -3; // 取钱数目大于银行卡账户余额 68 } else { 69 // 除此之外,都是正常状态 70 try { 71 Thread.sleep(1000); 72 } catch (InterruptedException e) { 73 e.printStackTrace(); 74 } // 休眠1秒钟,模拟取钱的时间 75 money -= number; // 取钱后的账户余额 76 System.out.println("余额:" + money); 77 } 78 } 79 return number; 80 } 81 82 }