java 去除干扰_Java线程并发干扰问题及解决方式(锁对象)

并发干扰

使用多线程开发可以很好地提高代码效率,但是在多线程对同一数据资源的共享中,许多线程需要的同一个数据做读写修改操作,因此必然会存在竞争问题,而且这些问题通常会带来灾难性的后果,我们来看一个例子:

现在有一个多线程的银行账户管理系统,我的账户内有余额 1000 元,现在有两个线程对我的账户进行操作:

线程 A :存入500元

线程 B :取出200元

我们应该知道,在大多服务器操作系统中都采用抢占式调度(线程状态及属性),每个线程只有一个时间片来执行任务,当时间片用完后会立刻暂停运行交由其他线程,然后再重新排队

在这种情况下,线程 A 和线程 B,可能就会产生冲突: 我们会发现,到最后我的账户只剩了800元,完全忽略了存钱的操作,这肯定不行!

锁对象

为解决代码块并发访问干扰,有两种机制:一种是 Java 提供的 synchronized 关键字,另一种是 ReentrantLock 类(唯一实现了 Lock 接口的对象)。我们来看看利用ReentrantLock 类如何解决这一问题

ReentrantLock

用 ReentrantLock 保护代码块的基本结构:

myLock.lock(); // 一个 ReentrantLock 对象

try{

...

}

finally{

myLock.unlock(); // 确保即使出现异常,也能解锁

}

这种方法理解起来其实很简单,我们可以把 lock 到 unlock 之间的区域想象成一个封锁区,任何一个线程一旦调用 lock,那么在它 unlock 之前, 其他任何线程都不能进入这段封锁区 如果有这么一个锁对象来保护我的代码,那么之前的问题就会变成这样: 这样一来,多线程共享资源就安全多了

我们要注意,在这里的锁对象只是针对我的账户的对象,不同的账户会有自己不同的锁对象,而线程操作不同的账户时,线程之间互不影响

还要注意,锁对象可以嵌套使用,线程可以重复获得已经持有的锁,锁会保持一个持有计数,用来跟踪 lock 方法的嵌套调用,线程每调用一次 lock 方法都还要调用 unlock 方法来解锁

ReentrantLock( ):构建一个可以被用来保护临界区的可重入的锁

ReentrantLock( boolean fair ):构建一个带有公平策略的锁,一个公平锁会偏向于等待时间长的线程,但是这一公平机制会大大降低性能,所以,默认情况下,锁没有被强制为公平的

ReentrantReadWriteLock(读/写锁)

Lock readLock( ) : 得到一个可以被多个读操作共用的读锁,但会排斥所有写操作

Lock writeLock( ):得到一个写锁,排斥所有其他读操作和写操作

使用 ReentrantReadWriteLock 必要步骤:

private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

private Lock readLock = rwl.readLock();

private Lock readLock = rwl.writeLock();

// 对所有读取方法加读锁

public double getTotalBalance() {

readLock.lock();

try {...}

finally { readLock.unlock(); }

}

// 对所有修改方法加写锁

public void transfer(...) {

writeLock.lock();

try {...}

finally { writeLock.unlock(); }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值