1700451469
1700451470
//异常处理
1700451471
1700451472
}finally{
1700451473
1700451474
//释放锁
1700451475
1700451476
lock.unlock();
1700451477
1700451478
}
1700451479
1700451480
}
1700451481
1700451482
上面代码中使用tryLock实现了自旋锁(Spin Lock),它跟互斥锁一样,如果一个执行单元要想访问被自旋锁保护的共享资源,则必须先得到锁,在访问完共享资源后,也必须释放锁。如果在获取自旋锁时,没有任何执行单元保持该锁,那么将立即得到锁;如果在获取自旋锁时锁已经有保持者,那么获取锁操作将“自旋”在那里,直到该自旋锁的保持者释放了锁为止。在我们的例子中就是线程A等待线程B释放锁,在2秒内不断尝试是否能够获得锁,达到2秒后还未获得锁资源,线程A则结束运行,线程B将获得资源继续执行,死锁解除。
1700451483
1700451484
对于死锁的描述最经典的案例是哲学家进餐(五位哲学家围坐在一张圆形餐桌旁,人手一根筷子,做以下两件事情:吃饭和思考。要求吃东西的时候停止思考,思考的时候停止吃东西,而且必须使用两根筷子才能吃东西),解决此问题的方法很多,比如引入服务生(资源调度)、资源分级等方法都可以很好地解决此类死锁问题。在我们Java多线程并发编程中,死锁很难避免,也不容易预防,对付它的最好办法是测试:提高测试覆盖率,建立有效的边界测试,加强资源监控,这些方法能使死锁无处遁形,即使发生了死锁现象也能迅速查找到原因,提高系统的可靠性。
1700451485
1700451486
1700451487
1700451488
1700451490
编写高质量代码:改善Java程序的151个建议 建议129:适当设置阻塞队列长度
1700451491
1700451492
阻塞队列BlockingQueue扩展了Queue、Collection接口,对元素的插入和提取使用了“阻塞”处理,我们知道Collection下的实现类一般都采用了长度自行管理方式(也就是变长),比如这样的代码是可以正常运行的:
1700451493
1700451494
public static void main(String[]args){
1700451495
1700451496
//定义初始长度为5
1700451497
1700451498
List<String>list=new ArrayList<String>(5);
1700451499
1700451500
//加入10个元素
1700451501
1700451502
for(int i=0;i<10;i++){
1700451503
1700451504
list.add(””);
1700451505
1700451506
}
1700451507
1700451508
}
1700451509
1700451510
上面的代码定义了列表的初始长度为5,在实际使用时,当加入的元素超过初始容量时,ArrayList会自行扩容,确保能够正常加入元素。那BlockingQueue也是集合,也实现了Collection接口,它的容量是否会自行管理呢?我们来看代码:
1700451511
1700451512
public static void main(String[]args)throws Exception{
1700451513
1700451514
//定义初始长度为5
1700451515
1700451516
BlockingQueue<String>bq=new ArrayBlockingQueue<String>(5);
1700451517
1700451518
//加入10个元素
[
上一页 ]
[ :1.700451469e+09 ]
[
下一页 ]