14.5 同步

14.5同步

多线程应用中,两个线程都调用修改某对象状态的方法。根据各线程访问数据次序,会产生讹误现象,该情况为竞争条件。

模拟银行账户相互随机转账,将转帐方法tranafer放到runnable中的run方法中,不断执行。

通过账户总金额判断多次转账中有无发生错误。

2个线程同时更新命令,accounts[to] += amount;

非原子操作,该命令有三个步骤,1将axcounts[to]加载到寄存器;2增加amount;3.将结果写回accounts[to].

一个线程执行步骤1和2,被剥夺运行权,第二个线程被唤醒修改了accounts数组中的同一项,之后第一个线程唤醒并完成3步。

上述动作擦除了第二个线程做的更新。

正常情况,最后一步要基于第二步更新的值进行加和。

两种机制防止代码块受并发访问干扰。

1.ReentrantLock类;2.sychronized关键字

RentrantLock保护代码块结构:

myLock.lock();

try{待执行的代码块}

finally{myLock.unlock} // 把解锁操作放到finally字句内至关重要,防堵塞

bank类加锁提前声明:private Lock bankLock = new ReentrantLock();、

锁可重入,锁保持持有计数跟踪对lock方法的嵌套调用。持有计数变为0时,线程释放锁。

一个锁对象可以有一个或多个相关的条件对象。当条件不满足时调用.await()。如转账时获得了锁,但发现账号余额不够:private Condition sufficientFunds; sufficientFunds = blankLock.newCondition(); 发现余额不足时调用sufficientFunds.await().进入该条件的等待集。

当锁可用时,不能马上解除阻塞,需等其他线程调用同一个条件上的signalAll方法:sufficientFunds.signalAll()。signalAll不会立即激活一个等待线程,仅仅解决线程的阻塞,当前线程推出同步方法后,这些线程通过竞争实现对对象的访问。

synchronized关键字。在方法声明时加该关键字,放在访问关键字后,非显示锁

同步阻塞,使用一个对象的锁实现额外的原子操作,transfer内部实现 synchronized(accounts)

volatile关键字为实力域的同步访问提供免锁机制。声明时编译器和虚拟机知道该域可能被另一个线程并发更新。举例布尔变量done的setDone和isDone方法。

final变量定义域,也可安全访问。

原子性,java.util.concurrent.atomic提供的方法可供原子性自增自减。原子性操作,操作不可被中断,要么执行,要么不执行。

死锁,相互等待(向对方账户赚钱,两个账户钱都不够)。

你可能感兴趣的:(java,jvm,开发语言)