面试题:请写出线程同步相关的方法,以银行账号存储款为例

一.该面试题主要考察多线程中的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

 

posted @ 2017-10-24 21:51  SummerChill  阅读(838)  评论(0编辑  收藏  举报