在尚未出现java.util.concurrent套件以前,多执行绪的程序都需要自己设计wait(), notify(), notifyAll()等程序,一个设计不良还可能造成死结(deadlock)的状况。
在JDK5以後,就可以使用现成的java.util.concurrent套件来更便利的撰写多执行绪相关程序。
Lock介面常用的实作类别为ReentrantLock,可以透过呼叫lock()方法让执行绪取得锁,并以呼叫unlock()来释放锁:
private Lock lock = new ReentrantLock();
private Object[] array;
private int next;
public void add(E e){
lock.lock();
try{
if(next == array.length){
array = Arrays.copyOf(array, array.length * 2);
}
array[next++] = e;
}finally{
lock.unlock();
}
}
除了基本的lock()以及unlock(),还有tryLock()方法,传回boolean,true表示可以取得锁,有了这个方法,原先产生死结的程序就可以透过呼叫tryLock()来解开死结。
由於写入动作是产生多执行绪资料混乱的罪魁祸首,若让其他读取的动作也都进行同样的锁定程序,会导致效能低下,这时就可以用ReadWriteLock来增进程序的效能。
其原理为,读取动作使用readLock()来进行锁定,写入动作使用writeLock()来进行锁定。
当有执行绪企图取得readLock时,只要物件的writeLock没有被取走,那就可以被拿走;
当有执行绪企图取得writeLock时,条件不只是writeLock没有被取走,连readLock也没有被取走时,才能允许执行绪取得writeLock。
上述的ReentrantReadWriteLock实作是比较严谨的执行绪锁定管控了,因为只要有任何执行绪再进行写入动作,也不能够读取,称为悲观读取(Pessimistic Reading)。假若我们的程序不需要这麽严格的管控呢?纵使被读取的物件状态会和真实状态不一样,但我们知道误差不会太大抑或是有误差我们无所谓,那就可以改用StampLock的实作类别。
long stamp = stampLock.tryOptimisticRead();
int num = array[i];
if(!stampLock.validate(stamp)){
stamp = stampLock.readLock();
try{
num = array[i];
}finally{
stampLock.unlockRead(stamp);
}
}
return num;
Condition的作用就是可以拥有不只一个物件的执行绪等待集,原生物件的wait(), notify()会共用该物件的等待集,所以不管执行绪原本是预备执行什麽动作,只要被叫进等待集,就是统一等待叫号;运用Condition物件的话,就可以依据需求将执行绪放进不同的等待集,当当前执行绪完成动作要教下一个来执行的时候,可以精准呼叫出该流程等待集中的执行绪,减少整体程序呼叫到无用执行绪的效能。
private Lock lock = new ReentrantLock();
private Condition aCondition = lock.newCondition();
private Condition bCondition = lock.newCondition();
public void aMethod(){
lock.lock()
try{
isAOk();
doSomething();
bCondition.signal(); //相当於Object的notify()
}finally{
lock.unlock()
}
}
public void isAOk(){
if( someCondition() ){
aCondition.await(); //相当於Object的wait()
}
}
public void bMethod(){
lock.lock()
try{
isBOk();
doSomething();
aCondition.signal();
}finally{
lock.unlock()
}
}
public void isBOk(){
if( someCondition() ){
bCondition.await();
}
}
<<: Day 20 : 深度追踪 Depth-first-searh
SQL Server 1.一个一个TABLE去点,汇出Scripts 2.SQL Server 汇出...
如标题,这篇想教大家如何修改phpMyAdmin的帐号密码 因为phpMyAdmin的预设是不用输入...
上篇我们学习到了如何再AWS Console建立user跟Group,今天我们来继续看如何建立rol...
今天分享如何把图片放进先前的翻译及拍卖查询功能 在universalis上每个物品都会有张图片 点击...
接续昨天,来介绍第四种、第五种以及第六种方法! 4.代替Java String replace():...