java lock 实例_Java并发编程 - 锁Lock取款机场景实例

转自:http://www.verejava.com/?id=17236703718463

锁Lock取款机场景实例

Lock是一个接口,ReentrantLock是它的实现类,下面通过“取款机案例”来剖析它的4个常用方法。

00f011ed9e79b0b05452d52335b1e961.png

1.爸爸妈妈同时在ATM上登录取款(不加任何锁)

public classBank {private static double money = 10000;public voidlogin(Thread currentUserThread) {

System.out.println(Thread.currentThread().getName()+ " 登录进入银行" + " 当前银行余额 : " +money);

}public voidlogout() {

System.out.println(Thread.currentThread().getName()+ " 退出银行");

}public double withdraw(doublewithdrawMoney) {if (this.money

System.out.println(Thread.currentThread().getName()+ " 当前银行余额 : " + this.money + " 余额不够");return 0;

}this.money -=withdrawMoney;

System.out.println(Thread.currentThread().getName()+ " 取款 : " + withdrawMoney + " 当前银行余额 : " + this.money);returnwithdrawMoney;

}

}

public classTestLock {public static voidmain(String[] args) {final Bank bank = newBank();//启动爸爸线程

Thread fatherThread = new Thread("爸爸") {public voidrun() {try{//爸爸登录

bank.login(Thread.currentThread());//过2秒取10000

Thread.sleep(2000);

bank.withdraw(10000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}

};

fatherThread.start();//启动妈妈线程

Thread motherThread = new Thread("妈妈") {public voidrun() {try{//妈妈登录

bank.login(Thread.currentThread());//过5秒取 10000

Thread.sleep(5000);

bank.withdraw(10000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}

};

motherThread.start();

}

}

结果:

妈妈 登录进入银行 当前银行余额 : 10000.0爸爸 登录进入银行 当前银行余额 :10000.0爸爸 取款 :10000.0 当前银行余额 : 0.0妈妈 当前银行余额 :0.0 余额不够

妈妈登录显示银行余额为10000,但是当她取钱时却显示“余额不足”,产生了数据不一致。

2.同一时刻,爸爸或妈妈线程只能有一个能够登录银行取款(获取lock()),另外一个线程需要等待, 直到unlock()释放锁

public classBank {private static double money = 10000;private Lock lock = newReentrantLock();public voidlogin(Thread currentUserThread) {

lock.lock();//登录加锁

System.out.println(Thread.currentThread().getName() + " 登录进入银行" + " 当前银行余额 : " +money);

}public voidlogout() {

lock.unlock();//退出释放锁

System.out.println(Thread.currentThread().getName() + " 退出银行");

}public double withdraw(doublewithdrawMoney) {if (this.money

System.out.println(Thread.currentThread().getName()+ " 当前银行余额 : " + this.money + " 余额不够");return 0;

}this.money -=withdrawMoney;

System.out.println(Thread.currentThread().getName()+ " 取款 : " + withdrawMoney + " 当前银行余额 : " + this.money);returnwithdrawMoney;

}

}

public classTestLock {public static voidmain(String[] args) {final Bank bank = newBank();//启动爸爸线程

Thread fatherThread = new Thread("爸爸") {public voidrun() {try{//爸爸登录

bank.login(Thread.currentThread());//过2秒取10000

Thread.sleep(2000);

bank.withdraw(10000);//爸爸退出

bank.logout();

}catch(InterruptedException e) {

e.printStackTrace();

}

}

};

fatherThread.start();//启动妈妈线程

Thread motherThread = new Thread("妈妈") {public voidrun() {try{//妈妈登录

bank.login(Thread.currentThread());//过5秒取 10000

Thread.sleep(5000);

bank.withdraw(10000);//妈妈退出

bank.logout();

}catch(InterruptedException e) {

e.printStackTrace();

}

}

};

motherThread.start();

}

}

结果:

爸爸 登录进入银行 当前银行余额 : 10000.0爸爸 取款 :10000.0 当前银行余额 : 0.0爸爸 退出银行

妈妈 登录进入银行 当前银行余额 :0.0妈妈 当前银行余额 :0.0余额不够

妈妈 退出银行

lock() 和unlock()成对出现,在login(Thread currentUserThread) 登录方法中调用 lock() ,在 logout()退出方法中调用了unlock()。

也就是说,Lock类的锁机制允许在不同的方法中加锁和解锁,而synchronized关键字只能在同一个方法中加锁和解锁。

3. 通过tryLock()判断是否可以获得锁, 能获得锁返回true,否则返回false

public classBank {private static double money = 10000;private Lock lock = newReentrantLock();public voidlogin(Thread currentUserThread) {//判断是否已经有线程登录

if (!lock.tryLock()) {

System.out.println(Thread.currentThread().getName()+ " 有人已经登录进入银行 请稍等");

}else{

System.out.println(Thread.currentThread().getName()+ " 登录进入银行" + " 当前银行余额: " +money);

}

}public voidlogout() {

lock.unlock();//退出释放锁

System.out.println(Thread.currentThread().getName() + " 退出银行");

}public double withdraw(doublewithdrawMoney) {if (this.money

System.out.println(Thread.currentThread().getName()+ " 当前银行余额: " + this.money + " 余额不够");return 0;

}this.money -=withdrawMoney;

System.out.println(Thread.currentThread().getName()+ " 取款: " + withdrawMoney + " 当前银行余额: " + this.money);returnwithdrawMoney;

}

}

public classTestLock {public static voidmain(String[] args) {final Bank bank = newBank();//启动爸爸线程

Thread fatherThread = new Thread("爸爸") {public voidrun() {try{//爸爸登录

bank.login(Thread.currentThread());//过2秒取10000

Thread.sleep(2000);

bank.withdraw(10000);//爸爸退出

bank.logout();

}catch(InterruptedException e) {

e.printStackTrace();

}

}

};

fatherThread.start();//启动妈妈线程

Thread motherThread = new Thread("妈妈") {public voidrun() {//妈妈登录

bank.login(Thread.currentThread());

}

};

motherThread.start();

}

}

结果:

妈妈 有人已经登录进入银行 请稍等

爸爸 登录进入银行 当前银行余额:10000.0爸爸 取款:10000.0 当前银行余额: 0.0爸爸 退出银行

4. 通过tryLock(long time,TimeUnit timeUnit)设置一段时间后重新进入

public classBank {private static double money = 10000;private Lock lock = newReentrantLock();public voidlogin(Thread currentUserThread) {//如果登录不成功,10秒后再重新尝试获得锁

try{if (!lock.tryLock(10, TimeUnit.SECONDS)) {

System.out.println(Thread.currentThread().getName()+ " 有人已经登录进入银行,请稍等");

}else{

System.out.println(Thread.currentThread().getName()+ " 登录进入银行" + " 当前银行余额: " +money);

}

}catch(InterruptedException e) {

e.printStackTrace();

}

}public voidlogout() {

lock.unlock();//退出释放锁

System.out.println(Thread.currentThread().getName() + " 退出银行");

}public double withdraw(doublewithdrawMoney) {if (this.money

System.out.println(Thread.currentThread().getName()+ " 当前银行余额: " + this.money + " 余额不够");return 0;

}this.money -=withdrawMoney;

System.out.println(Thread.currentThread().getName()+ " 取款: " + withdrawMoney + " 当前银行余额: " + this.money);returnwithdrawMoney;

}

}

public classTestLock {public static voidmain(String[] args) {final Bank bank = newBank();//启动爸爸线程

Thread fatherThread = new Thread("爸爸") {public voidrun() {try{//爸爸登录

bank.login(Thread.currentThread());//过2秒取10000

Thread.sleep(2000);

bank.withdraw(10000);//爸爸退出

bank.logout();

}catch(InterruptedException e) {

e.printStackTrace();

}

}

};

fatherThread.start();//启动妈妈线程

Thread motherThread = new Thread("妈妈") {public voidrun() {//妈妈登录

bank.login(Thread.currentThread());

}

};

motherThread.start();

}

}

结果妈妈10秒后重新尝试得到锁登录进入了银行 :

爸爸 登录进入银行 当前银行余额: 10000.0爸爸 取款:10000.0 当前银行余额: 0.0爸爸 退出银行

妈妈 登录进入银行 当前银行余额:0.0

5.如果爸爸线程调用 lock() 获得锁以后,没有unlock()释放锁,妈妈线程将会一直等待产生死锁,即使调用 interrupt()中断也没有作用。

public classBank {private static double money = 10000;private Lock lock = newReentrantLock();public voidlogin(Thread currentUserThread) {

lock.lock();

System.out.println(Thread.currentThread().getName()+ " 登录进入银行" + " 当前银行余额 : " +money);

}public voidlogout() {

lock.unlock();//退出释放锁

System.out.println(Thread.currentThread().getName() + " 退出银行");

}public double withdraw(doublewithdrawMoney) {if (this.money

System.out.println(Thread.currentThread().getName()+ " 当前银行余额: " + this.money + " 余额不够");return 0;

}this.money -=withdrawMoney;

System.out.println(Thread.currentThread().getName()+ " 取款: " + withdrawMoney + " 当前银行余额: " + this.money);returnwithdrawMoney;

}

}

public classTestLock {public static voidmain(String[] args) {final Bank bank = newBank();//启动爸爸线程

Thread fatherThread = new Thread("爸爸") {public voidrun() {try{//爸爸登录

bank.login(Thread.currentThread());//过2秒取10000

Thread.sleep(2000);

bank.withdraw(10000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}

};

fatherThread.start();//启动妈妈线程

Thread motherThread = new Thread("妈妈") {public voidrun() {try{

Thread.sleep(1000);

bank.login(Thread.currentThread());

}catch(InterruptedException e) {

System.out.println(Thread.currentThread().getName()+" 登录超时被中断");

}

}

};

motherThread.start();try{

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

motherThread.interrupt();

}

}

结果:

d68a77856fc3cd5c6ea3c3f47d919fc4.png

妈妈线程一直等待爸爸线程释放锁,结果造成死锁。妈妈线程调用motherThread.interrupt(); 中断也不起做用。

6. 在登录获得锁时,调用lockInterruptibly(),允许中断等待的线程,使motherThread.interrupt()可用。

public classBank {private static double money = 10000;private Lock lock = newReentrantLock();public void login(Thread currentUserThread) throwsInterruptedException {

lock.lockInterruptibly();//运行等待线程被中断

System.out.println(Thread.currentThread().getName() + " 登录进入银行" + " 当前银行余额 : " +money);

}public voidlogout() {

lock.unlock();//退出释放锁

System.out.println(Thread.currentThread().getName() + " 退出银行");

}public double withdraw(doublewithdrawMoney) {if (this.money

System.out.println(Thread.currentThread().getName()+ " 当前银行余额: " + this.money + " 余额不够");return 0;

}this.money -=withdrawMoney;

System.out.println(Thread.currentThread().getName()+ " 取款: " + withdrawMoney + " 当前银行余额: " + this.money);returnwithdrawMoney;

}

}

public classTestLock {public static voidmain(String[] args) {final Bank bank = newBank();//启动爸爸线程

Thread fatherThread = new Thread("爸爸") {public voidrun() {try{//爸爸登录

bank.login(Thread.currentThread());//过2秒取10000

Thread.sleep(2000);

bank.withdraw(10000);

}catch(InterruptedException e) {

e.printStackTrace();

}

}

};

fatherThread.start();//启动 妈妈 线程

Thread motherThread = new Thread("妈妈") {public voidrun() {try{

Thread.sleep(1000);

bank.login(Thread.currentThread());

}catch(InterruptedException e) {

System.out.println(Thread.currentThread().getName()+" 登录超时被中断");

}

}

};

motherThread.start();try{

Thread.sleep(2000);

}catch(InterruptedException e) {

e.printStackTrace();

}

motherThread.interrupt();

}

}

结果:

爸爸 登录进入银行 当前银行余额 : 10000.0妈妈 登录超时被中断

爸爸 取款:10000.0 当前银行余额: 0.0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值