一.该面试题主要考察多线程中的synchronized或者Lock的使用
* 线程同步 :使用同步方法,实现线程同步
* 同步synchronized方法的对象监视锁为this,当前对象
* 多个线程使用同一把锁,如果线程安全必需确保:多个线程使用的是同一个this对象(Runnable适用于共享同一对象[如:this],如果Thread继承就会有问题[推荐使用Runnable])
* 所有访问此对象方法的线程都在方法外等待,都会判断同步锁,降低效率,但确保线程安全问题
* java的每个对象都有一个内置锁,当用synchronized关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,线程需要获得内置锁,否则就处于阻塞状态
* synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类
此例子中使用synchronized关键字:
private synchronized void makeWithdraw(int amount){...}
二.上代码
BankAccount.java
1 public class BankAccount { 2 //余额 3 private int balance = 500; 4 //查询 5 public int getBalance(){ 6 return balance; 7 } 8 //取款 9 public void withdraw(int amount){ 10 balance = balance - amount; 11 } 12 //存款 13 public void deposit(int amount){ 14 balance = balance + amount; 15 } 16 }
SyncMethod.java
1 /** 2 * 此线程类实现Runnable接口 3 * 线程同步 :使用同步方法,实现线程同步 4 * 同步synchronized方法的的对象监视锁为this,当前对象 5 * 多个线程使用同一把锁,如果线程安全必需确保:多个线程使用的是同一个this对象 6 * 所有访问此对象方法的线程都在方法外等待,都会判断同步锁,降低效率,但确保线程安全问题 7 * */ 8 public class SyncMethod implements Runnable { 9 // 所有Thread多线程线程都共享Runnable(接口对象)和account对象 10 private BankAccount account = new BankAccount(); 11 @Override 12 public void run() { 13 for (int i = 0; i < 5; i++) {// 总共取款5次 14 makeWithdraw(100); // 每次取款100 15 if (account.getBalance() < 0) { 16 System.out.println("☆" + Thread.currentThread().getName()+ " 透支了!"); 17 } 18 } 19 } 20 21 /** 22 * makeWithdraw 账户取款 23 * @param amount取款金额 24 * 打印log记录取款过程 25 * */ 26 private synchronized void makeWithdraw(int amount){ 27 if(account.getBalance() >= amount){//如果余额足够则取款 28 System.out.println("☆" + Thread.currentThread().getName() + " 准备取款!"); 29 try { 30 Thread.sleep(500); 31 } catch (InterruptedException e) { 32 System.out.println(Thread.currentThread().getName() + " 准备取款,等待0.5s线程中断!" + e.getMessage()); 33 } 34 account.withdraw(amount); 35 System.out.println("☆" + Thread.currentThread().getName() + " 完成" + amount + "取款!余额为" + account.getBalance()); 36 }else{//余额不足则提示 37 System.out.println("☆" + "余额不足以支付" + Thread.currentThread().getName() + amount + " 的取款,余额为" + account.getBalance()); 38 } 39 } 40 }
TreadSyncTest.java
1 public class TreadSyncTest { 2 3 /* 4 Junit不适合多线程并发测试。 5 因为线程还在激活状态的时候,Junit已经执行完成。 6 在Junit的TestRunner中,它没有被设计成搜寻Runnable实例, 7 并且等待这些线程发出报告,它只是执行它们并且忽略了它们的存在。 8 综上,不可能在Junit中编写和维护多线程的单元测试。 9 */ 10 /* 11 @Test 12 public void test() { 13 } 14 */ 15 16 public static void main(String[] args) { 17 //实现Runnable:所有Thread多线程线程都共享Runnable(接口对象) 18 //NoSync target =new NoSync(); 19 SyncMethod target = new SyncMethod(); 20 //创建罗密欧和朱丽叶两个线程实现取款(同时) 21 Thread romeoThread = new Thread(target); 22 romeoThread.setName("罗密欧"); 23 Thread julietThread = new Thread(target); 24 julietThread.setName("朱丽叶"); 25 //调用Thread对象的start()方法,启动线程,执行run()方法(OS) 26 romeoThread.start(); 27 julietThread.start(); 28 } 29 }
运行结果:
正常运行结果1: ☆罗密欧 准备取款! ☆罗密欧 完成100取款!余额为400 ☆罗密欧 准备取款! ☆罗密欧 完成100取款!余额为300 ☆罗密欧 准备取款! ☆罗密欧 完成100取款!余额为200 ☆罗密欧 准备取款! ☆罗密欧 完成100取款!余额为100 ☆罗密欧 准备取款! ☆罗密欧 完成100取款!余额为0 ☆余额不足以支付朱丽叶100 的取款,余额为0 ☆余额不足以支付朱丽叶100 的取款,余额为0 ☆余额不足以支付朱丽叶100 的取款,余额为0 ☆余额不足以支付朱丽叶100 的取款,余额为0 ☆余额不足以支付朱丽叶100 的取款,余额为0. 正常运行结果2: ☆罗密欧 准备取款! ☆罗密欧 完成100取款!余额为400 ☆罗密欧 准备取款! ☆罗密欧 完成100取款!余额为300 ☆罗密欧 准备取款! ☆罗密欧 完成100取款!余额为200 ☆罗密欧 准备取款! ☆罗密欧 完成100取款!余额为100 ☆朱丽叶 准备取款! ☆朱丽叶 完成100取款!余额为0 ☆余额不足以支付朱丽叶100 的取款,余额为0 ☆余额不足以支付朱丽叶100 的取款,余额为0 ☆余额不足以支付朱丽叶100 的取款,余额为0 ☆余额不足以支付罗密欧100 的取款,余额为0 ☆余额不足以支付朱丽叶100 的取款,余额为0 正常运行结果3: ☆罗密欧 准备取款! ☆罗密欧 完成100取款!余额为400 ☆罗密欧 准备取款! ☆罗密欧 完成100取款!余额为300 ☆罗密欧 准备取款! ☆罗密欧 完成100取款!余额为200 ☆朱丽叶 准备取款! ☆朱丽叶 完成100取款!余额为100 ☆朱丽叶 准备取款! ☆朱丽叶 完成100取款!余额为0 ☆余额不足以支付朱丽叶100 的取款,余额为0 ☆余额不足以支付朱丽叶100 的取款,余额为0 ☆余额不足以支付朱丽叶100 的取款,余额为0 ☆余额不足以支付罗密欧100 的取款,余额为0 ☆余额不足以支付罗密欧100 的取款,余额为0
如果不用synchronized关键字的结果:
☆罗密欧 准备取款! ☆朱丽叶 准备取款! ☆朱丽叶 完成100取款!余额为300 ☆罗密欧 完成100取款!余额为300 ☆罗密欧 准备取款! ☆朱丽叶 准备取款! ☆朱丽叶 完成100取款!余额为100 ☆朱丽叶 准备取款! ☆罗密欧 完成100取款!余额为100 ☆罗密欧 准备取款! ☆罗密欧 完成100取款!余额为0 ☆余额不足以支付罗密欧100 的取款,余额为0 ☆余额不足以支付罗密欧100 的取款,余额为0 ☆朱丽叶 完成100取款!余额为-100 ☆朱丽叶 透支了! ☆余额不足以支付朱丽叶100 的取款,余额为-100 ☆朱丽叶 透支了! ☆余额不足以支付朱丽叶100 的取款,余额为-100 ☆朱丽叶 透支了!
此博文转载并整理于:http://blog.csdn.net/typa01_kk/article/details/46738459