1.取款问题
比如你在银行里存了1000块,从银行柜台取出600,同时也在取款机取出600,正常的话第二次在取款机取款由于存款少于600所以取不出来,我们实践一下:
银行账户类
public class BankAccount { int money=1000; public int getMoney(int num) { if ( money<num) { return -1; } else { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } money -= num; System.out.println("剩了"+money); return money; } } }
线程类
class ThreadBank extends Thread { BankAccount myAccount; ThreadBank(BankAccount myAccount) { this.myAccount = myAccount; } @Override public void run() { if(myAccount.getMoney(600)!=-1){ System.out.println("取款成功"); }else{ System.out.println("余额不足,不能取款"); } } }
测试类
public static void main(String[] args) { BankAccount myAccount= new BankAccount(); ThreadBank thread1=new ThreadBank(myAccount); ThreadBank thread2=new ThreadBank(myAccount); thread1.start(); thread2.start();}
结果
剩了400 取款成功 剩了-200 取款成功
从程序结果可以看出两次取钱都成功了,这就是线程同步导致的问题。
2.解决取款同步问题
利用sychronized关键字解决同步问题,Synchronized关键字:
当synchronized关键字修饰一个方法的时候,该方法叫做同步方法。
Java中的每个对象都有一把锁(lock)或者监视器。当访问某个对象的synchronized方法时,表示将该对象上锁,此时其他任何线程都无法再访问该synchronied方法了,直到之前的那个线程执行方法完毕后(或者抛出了异常),那么将该对象的锁释放掉,其他线程才有可能再去访问该synchronized方法
注意:如果一个对象有多个synchronized方法,某一时刻某个线程已经进入到某个synchronized方法,那么在该方法没有执行完毕前,其他线程是无法访问该对象的任何synchronized方法的。
1)在getMoney方法前面加入synchronized加入关键字
public class BankAccount { int money=1000; public synchronized int getMoney(int num) { if ( money<num) { return -1; } else { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } money -= num; System.out.println("剩了"+money); return money; } } }
2) static synchronized方法
如果某个synchronized方法是static的,那么当线程访问该方法时,它锁的并不是synchronized方法所在的对象,而是synchronized方法所在的对象所对应的Class对象,因为Java中无论一个类有多少个对象,这些对象会对应唯一一个Class对象,因此当线程分别访问同一个类的两个对象的两个static,synchronized方法时,他们的执行顺序也是顺序的,也就是说一个线程先去执行方法,执行完毕后另一个线程才开始执行
静态synchronized方法
class Bank { public static synchronized void getMoney() { for (int i = 0; i < 10; i++) { System.out.println("===== " + i); } }
线程类
class ThreadStatic extends Thread { Bank bank; ThreadStatic(Bank bank) { this.bank = bank; } @Override public void run() { bank.getMoney(); } }
测试类
public static void main(String[] args) { Bank bank1 = new Bank(); Bank bank2 = new Bank(); ThreadStatic thread1 = new ThreadStatic(bank1); ThreadStatic thread2 = new ThreadStatic(bank2); thread1.start(); thread2.start(); }
结果
===== 0 ===== 1 ===== 2 ===== 3 ===== 4 ===== 5 ===== 6 ===== 7 ===== 8 ===== 9 ===== 0 ===== 1 ===== 2 ===== 3 ===== 4 ===== 5 ===== 6 ===== 7 ===== 8 ===== 9
把static去掉,大家可以实践一下
3)Synchronized块写法
Synchronized(object){}表示线程执行的时候对object上锁
class ThreadStatic extends Thread { Bank bank; ThreadStatic(Bank bank) { this.bank = bank; } @Override public void run() { bank.getMoney(); } }
This表示对本对象加锁
public static void main(String[] args) { Bank bank1 = new Bank(); ThreadStatic thread1 = new ThreadStatic(bank1); ThreadStatic thread2 = new ThreadStatic(bank1); thread1.start(); thread2.start(); }
两个线程调用同一个对象的方法,那么输出结果是什么呢,大家打印出来看一下,如果你没有写错的话,打印出来的结果肯定是按顺序执行的。
Synchronized方法和方法块写法区别:
Synchonized方法是一种粗粒度的并发控制,在某一时刻只能有一个线程执行该synchronized方法,synchronized块则是一种细粒度的并发控制,只会将块中的代码同步,位于方法内、synchronized块之外的代码是可以被多个线程同时访问到的
相关推荐
银行账户的存取款线程设计银行账户的存取款线程设计
主要介绍了以银行取钱为例模拟Java多线程同步问题完整代码,具有一定借鉴价值,需要的朋友可以参考下。
简单实现线程的异步操作,简单易懂,下载VS2010 直接运行可看效果
本章内容 掌握同步代码块的使用 掌握同步方法的使用 理解线程死锁 掌握 ThreadLocal 类的使用 使用多线程模拟猴子采花 使用同步方法模拟购票 使用多线程模拟购物订单生成 使用 ThreadLocal 类模拟银行取款 Java高级...
3.掌握多线程的同步机制。 实验内容 根据要求,编写应用程序。要求如下: 1.模拟银行账户,两个以上的用户同时进行存、取操作。 2.银行有一个账户,有两个用户分别向同一个账户存3000元,每次存1000,存三次。 3....
你多线程做的一个ATM模拟测试程序 (仅供参考)
c语言下实现模拟ATM机的过程,包括存钱取钱、查询、积分等,可以同时管理5个账户
JAVA线程同步通信银行存取款,银行账户的存取款线程设计,本例涉及银行账户类、存款类、取款类。实际意图是:使存钱和取钱构成一种关系——只有存钱后且账上有钱才能取钱,并且只有取钱后才能存钱。
此项目是对银行业务调度系统的模拟(也是一道面试题的解),附件中为VB源代码,直接在VB6的IDE中运行即可演示效果。
同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读写)。 异步 : 委托一小弟拿银行卡到银行取钱,然后给你(使用异步IO时,Java将IO读写委托给OS处理,需要将数据缓冲区地址和大小传给OS...
● 软件不存在磨损和老化问题,但存在退化问题; ● 软件产品的生产主要是脑力劳动; ● 软件产品的成本非常昂贵,其开发方式目前尚未完全摆脱手工生产方式; ● 软件具有“复杂性”,其开发和运行常受到...
当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket。 QQ客户端登录界面,中部有三个JPanel,有一个叫选项卡窗口管理。还可以更新...
Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个...