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

Posted guiququ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了软件构造复习内容(10)---并发相关的知识,希望对你有一定的参考价值。

保证线程安全的策略:

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

策略1.限制数据共享

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

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

  避免全局可变变量

2.共享不可变数据

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

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

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

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

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

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

  技术图片

 

 

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

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

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

4.锁和同步

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

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

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

  技术图片

 

 

    Monitor Pattern

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

  使用ADT自己做lock

  技术图片

 

 

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

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

  加锁的原则:

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

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

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

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

    技术图片

    死锁:

    发生的条件

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

          死锁的例子:

      技术图片

 

 

   solution

      1.按顺序锁

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

      

 

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

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

      条件对象的方法

      void await()

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

      void singalAll()

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

      void singal()

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

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

      void wait() 

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

      void notify()

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

      void notifyAll();    

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

    技术图片

 

 

    技术图片

 

  

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

 

说明线程安全的规约

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

  采取了哪一种策略?

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

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

以上是关于软件构造复习内容(10)---并发的主要内容,如果未能解决你的问题,请参考以下文章

软件构造复习内容--ADT

软件构造(复习)——一些关于多线程的知识

软件构造复习内容--Process and Tools of Software Construction

软件构造复习内容---面向复用的设计模式

软件构造期末复习考点总结

哈工大软件构造复习——LSP原则,协变和逆变