1.状态依赖性
在一个单线程环境中,如果调用一个方法之前 没有满足进入该方法的先决条件(比如要去一个空的队列里获取对象),那么这个方法就永远不能进入。因为这个先决条件永远不会改变,所以这个方法就只能返回失败了。该方法依赖对象的状态。
而在多线程的环境中,这个先决条件很有可能被其他线程所改变,例如A线程想要从一个空的连接池中获取一个连接,当然此刻A线程的操作是失败的,但是后续的B线程归还了一个连接对象,这时如果A线程再去尝试的话会成功。下面有几种方法来实现为客户端构建获取连接的方法。
1.1 轮询重试(sleep)
public V take(){
//先获取保护对象状态的锁,使得在接下来的操作中对象的状态不会被改变。
acquire lock on object
//判断对象状态是否满足先决条件(此时是容器中没有对象了)
while(state not hold){
//不满足条件则释放锁,等待其他线程能过获取锁并改变对象状态(别的线程能够添加对象)
release lock
//当前线程等待一段时间
wait for preconditon might hold
//重新尝试获取锁,继续轮询
reacquire lock
}
//此时是已经获取了条件的 可以进行业务逻辑
V v=doTavke();
//释放锁
release lock;
return v;
}
轮询休眠费力不讨好的解决状态依赖性的问题。鬼知道你唤醒的时候,当前的状态是否是满足你的条件呢?这样导致线程频繁进行上下文切换,累死cpu了。或者你睡过头了呢(线程休眠的时候状态已经满足了,没有及时的醒来)。
轮询休眠间隔时间越小性能越好,cpu消耗越高。时间间隔越大,性能越差,cpu消耗越小