Java并发编程实战
来源:互联网 发布:mac 启动ipython 编辑:程序博客网 时间:2024/05/01 13:22
安全性问题是多线程开发的首要问题,为了保证线程安全,往往使用加锁机制。但过度使用锁或不正确使用锁,可能导致死锁等活跃性问题。
线程活跃性问题有:
- 死锁
- 饥饿
- 槽糕的响应性
- 活锁
死锁的原因和解决方案
最常见的活跃性问题是死锁。
死锁最常见的原因是不正确的锁顺序。
- 锁顺序死锁
- 原因:多个锁的循环加锁依赖,如A线程持有一个锁,等待B线程持有的另外一个锁,同时B线程正等待A线程持有的锁。
- 解决方法:按照相同的顺序来请求锁。
- 动态锁顺序死锁
- 原因:锁的顺序取决于传递的参数顺序。
- 解决方法:使用散列值(System.identityHashCode方法)和加时锁方式避免死锁
- 协作对象之间发生死锁
- 原因:在持有锁时调用外部方法,在外部方法中要获得另外的锁。
- 解决方法: 开放调用 (Open Call), 即调用某个方法时不需要持有锁(使用同步块仅被用于保护涉及可变共享状态的操作)。
- 资源死锁
- 原因:1) 在相同的资源集合上等待; 2)线程饥饿死锁,如一个任务依赖其他任务的结果。
死锁的避免和诊断
- 获取多锁时的顺序保持一致。
- 使用开放调用。
- 使用限时的显式锁 (Lock的tryLock方法)。
- 通过线程转储信息来分析死锁。
饥饿
线程由于无法访问它所需的资源而不能继续执行,如线程的优先级使用不当,或程序进入无限循环。
避免使用线程优先级。
槽糕的响应性
将运行时间较长的线程放到后台,并降低它的优先级。
活锁
同常发生在处理事务消息的应用程序中。当多个互相协作的线程对彼此进行响应从而修改各自的状态,并使得任何一个线程无法继续执行时。
解决方法是引入随机性,如让它们分别等待一段随机时间。
示例: 通过开发调用来避免在相互协作的对象之间产生死锁。
class CooperatingNoDeadlock { class Taxi { private Point location, destination; private final Dispatcher dispatcher; public Taxi(Dispatcher dispatcher) { this.dispatcher = dispatcher; } public synchronized Point getLocation() { return location; } public synchronized void setLocation(Point location) { boolean reachedDestination; synchronized (this) { this.location = location; reachedDestination = location.equals(destination); } if (reachedDestination) dispatcher.notifyAvailable(this); } public synchronized Point getDestination() { return destination; } public synchronized void setDestination(Point destination) { this.destination = destination; } } class Dispatcher { private final Set<Taxi> taxis; private final Set<Taxi> availableTaxis; public Dispatcher() { taxis = new HashSet<Taxi>(); availableTaxis = new HashSet<Taxi>(); } public synchronized void notifyAvailable(Taxi taxi) { availableTaxis.add(taxi); } public Image getImage() { Set<Taxi> copy; synchronized (this) { copy = new HashSet<Taxi>(taxis); } Image image = new Image(); for (Taxi t : copy) image.drawMarker(t.getLocation()); return image; } } class Image { public void drawMarker(Point p) { } }}
0 0
- Java并发编程实战
- Java并发编程实战--
- Java并发编程实战-
- Java 并发编程实战
- java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- BZOJ4034: [HAOI2015]树上操作
- Request Archive Demo
- NYOJ 308
- [BZOJ1455]罗马游戏 左偏树+并查集
- linux exercise 10
- Java并发编程实战
- SSM:Context initialization failed
- struts+hibernate+oracle+easyui实现lazyout组件的简单案例——Dept实体类和对应的配置信息
- Android体系与系统架构
- ssdb leveldb ldb文件恢复 ext4magic extundelete
- 生产者和消费者
- Qt获取CPU序列号(最简单的方式)
- struts+hibernate+oracle+easyui实现lazyout组件的简单案例——hibernate的config文件(hibernate.cfg.xml)
- 【bzoj1014】[JSOI2008]火星人prefix