软件构造复习内容(10)---并发(2)

保证线程安全的策略:

保证线程安全,就要避免Race Condition,竞争的存在能破坏ADT的RI,使数据混乱。

策略1.限制数据共享

将可变数据限制在单一线程内部,避免竞争,不允许任何线程直接读写数据。

核心思想:线程之间不共享mutable的数据类型

避免全局可变变量

2.共享不可变数据

使用不可变数据类型和不可变引用,避免多线程之间的race condition

关键词 final有用,只允许读,不允许写

不可变数据通常是线程安全的。

对于并发而言,有益的改变也是可能引起Race Condition的,需要加锁保证安全。

3.使用线程安全的数据类型

JDK提供了一些可变的线程安全的对象,这些对象对他们的每一个操作调用,都是以原子方式执行的,不会与其他操作交错(interleaving)

软件构造复习内容(10)---并发(2)

   在使用了线程安全的包装器产生的对象之后,不要把原对象分享给其他线程,不要保留别名,一定要彻底销毁。

即使是在线程安全的集合类上,使用迭代器仍然是不安全的,除非使用lock机制,当时用迭代器访问集合时,当别的线程修改集合时,迭代器会失效,并抛出ConcurrentModificationException异常。

这个线程安全的数据类型只能保证其上某个操作是线程安全的,但是如果多个操作放在一起,仍旧不安全。

4.锁和同步

  使用锁的机制,获得对数据独家修改权利,其他的线程均为被阻塞,不得访问。

  拥有Lock的线程可独占式的执行该部分代码。其他的线程被阻塞直到锁被释放

  注意要保证互斥,需要使用同一个锁

软件构造复习内容(10)---并发(2)

    Monitor Pattern

一个监视器是一个类,它的所有方法都被人为的独占,所以在一个时间内只能有一个线程使用它的实例。

使用ADT自己做lock

软件构造复习内容(10)---并发(2)

   同步机制会给性能带来极大影响,除非必要,否则不要使用

因此,需要尽可能减小lock的范围,避免在方法签名中加入synchronized,而且在方法代码内部更加精细的区分哪些代码有可能有threadsafe危险,为其加锁。

加锁的原则:

  任何共享的mutable变量/对象必须被锁保护

  涉及到多个mutable变量时,他们必须被同一个lock保护。

  monitor pattern下,ADT的所有方法都要被同一个synchronized(this)保护

实现更大的原子操作:通过锁

  软件构造复习内容(10)---并发(2)

  死锁:

  发生的条件

    1.多个线程使用多个锁,且多个线程使用锁的顺序不同,可能就会导致互相等待对方释放锁,从而都无法运行下去而终止

        死锁的例子:

    软件构造复习内容(10)---并发(2)

 solution

    1.按顺序锁

    2.粗密度的锁,只是用一个锁  

    

  2.解锁的时没有解除所有线程的因这个锁而造成的阻塞状态

    没有使用signalAll方法,而是换成了singal方法

    条件对象的方法

    void await()

    将该线程放到条件的等待集中

    void singalAll()

    解除该条件的等待集中所有线程的阻塞状态。

    void singal()

    随机解除一个该条件等待集中一个线程的阻塞状态

     在同步方法(使用synchronized关键字)中使用的wait方法,同步方法使用内部锁,只有一个条件对象

    void wait() 

    导致线程进去等待状态,该方法只能在一个同步方法或同步模块中调用

    void notify()

    随机选择一个在该对象上调用wait方法的线程,解除其阻塞状态,只能在同步方法或同步模块中使用。

    void notifyAll();    

    解除所有在该对象上调用wait方法的线程的阻塞状态,只能在同步方法和同步模块中使用。

  软件构造复习内容(10)---并发(2)

  软件构造复习内容(10)---并发(2)

  当发现目前的数据情况无法执行方法时,可以将自己wait,释放锁(notify or notifyAll)让别人先执行

说明线程安全的规约

在代码中以注释的形式增加说明:该ADT采用了什么设计决策来保证线程安全。

采取了哪一种策略?

如果是后两种,还需要考虑对数据的访问都是原子的,不存在交错(interleaving)

限制数据共享(策略1)通常不是好策略,因为该策略要避免所有可变数据的共享,除非知道线程访问的所有数据,否则就无法彻底保证线程安全。

相关推荐