锁对象

本文介绍了Java中防止并发访问的两种机制,重点讨论了关键字及其在Java SE 5.0中引入的类。内容包括锁的自动提供、条件、线程阻塞和锁的重入特性。通过模拟银行转账的例子,解释了锁如何确保并发操作的正确性,特别是当多个线程访问同一Bank对象时,锁以串行方式提供服务,保证了数据的一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 有两种机制防止代码块受并发访问的干扰。Java语言提供一个synchronized关键字达到这一目的,并且Java SE 5.0引入了ReentrantLook类。synchronized关键字自动提供一个锁以及相关的"条件",对于大多数需要显式锁的情况,这是很便利的。java.util.concurrent框架为这些基础机制提供了独立的类。
  • 如果使用锁来保护模拟银行转账中的Bank类的transfer方法
public class Bank {
    private Lock bankLock = new ReentrantLock();
    //把钱从一个帐户转到另一个帐户
    public void transfer(int from, int to, double amount)
    {
        bankLock.lock();
        try{
            if (accounts[from] < amount) return;
            System.out.print(Thread.currentThread());
            accounts[from] -= amount;
            System.out.printf(" %10.2f from %d to %d", amount, from, to);
            accounts[to] += amount;
            System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
        }finally {
            bankLock.unlock();
        }
    }
}
  • 假定一个线程调用transfer,在执行结束前被剥夺了运行权。假定第二个线程也调用了transfer,由于第二个线程不能获得锁,将在调用lock方法时被阻塞。它必须等待第一个线程完成transfer方法的执行之后才能再度被激活。当第一个线程释放锁时,那么第二个线程才开始运行。
    非同步线程与同步线程的比较
  • 注意每一个Bank对象有自己的ReentrantLock对象。如果两个线程试图访问同一个Bank对象,那么锁以串行方式提供服务。但是,如果两个线程访问不同的Bank对象,每个线程得到不同的锁对象,两个线程都不会发生阻塞。本该如此,因为线程在操纵不同的Bank实例的时候,线程之间不会相互影响。模拟银行转账就是使用同一个Bank对象,才能控制余额不会出现讹误。
  • 锁是可以重入的,因为线程可以重复地获得已经持有的锁。锁保持一个持有计数来跟踪对lock方法的嵌套调用。线程在每一次调用lock都要调用unlock来释放锁。由于这一特性,被一个锁保护的代码可以调用另一个使用相同的锁的方法。例如,transfer方法调用getTotalBalance方法,这也会封锁bankLock对象,此时bankLock对象的持有计数为2。当getTotalBalance方法退出的时候,持有计数变回1.当transfer方法退出的时候,持有计数变为0。线程释放锁。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值