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
原创粉丝点击