zoukankan      html  css  js  c++  java
  • java并发编程实战《七》安全性、活跃性以及性能问题

    安全性、活跃性以及性能问题

    安全性问题

      那什么是线程安全呢?其实本质上就是正确性,而正确性的含义就是程序按照我们期望的执行,不要让我们感到意外。

      存在共享数据并且该数据会发生变化,通俗地讲就是有多个线程会同时读写同一数据

      那如果能够做到不共享数据或者数据状态不发生变化,不就能够保证线程的安全性了嘛。有不少技术方案都是基于这个理论的,例如线程本地存储(Thread Local Storage,TLS)、不变模式等等

      当多个线程同时访问同一数据,并且至少有一个线程会写这个数据的时候,如果我们不采取防护措施,那么就会导致并发 Bug,对此还有一个专业的术语,叫做数据竞争

      竞态条件,指的是程序的执行结果依赖线程执行的顺序

      那面对数据竞争竞态条件问题,又该如何保证线程的安全性呢?其实这两类问题,都可以用互斥这个技术方案,而实现互斥的方案有很多,CPU 提供了相关的互斥指令,操作系统、编程语言也会提供相关的 API。从逻辑上来看,我们可以统一归为:

    活跃性问题

      所谓活跃性问题,指的是某个操作无法执行下去。我们常见的“死锁”就是一种典型的活跃性问题,当然除了死锁外,还有两种情况,分别是“活锁”和“饥饿”

      发生“死锁”后线程会互相等待,而且会一直等待下去,在技术上的表现形式是线程永久地“阻塞”了。

      有时线程虽然没有发生阻塞,但仍然会存在执行不下去的情况,这就是所谓的“活锁”。

      解决“活锁”的方案很简单,谦让时,尝试等待一个随机的时间就可以了。

      那“饥饿”该怎么去理解呢?所谓“饥饿”指的是线程因无法访问所需资源而无法执行下去的情况。

      

      解决“饥饿”问题的方案很简单,有三种方案:一是保证资源充足,二是公平地分配资源,三就是避免持有锁的线程长时间执行。这三个方案中,方案一和方案三的适用场景比较有限,因为很多场景下,资源的稀缺性是没办法解决的,持有锁的线程执行的时间也很难缩短。倒是方案二的适用场景相对来说更多一些。

      那如何公平地分配资源呢?在并发编程里,主要是使用公平锁所谓公平锁,是一种先来后到的方案,线程的等待是有顺序的,排在等待队列前面的线程会优先获得资源。

    性能问题

      “锁”的过度使用可能导致串行化的范围过大,这样就不能够发挥多线程的优势了.

      Java SDK 并发包里之所以有那么多东西,有很大一部分原因就是要提升在某个特定领域的性能。

    课后思考

      Java 语言提供的 Vector 是一个线程安全的容器,有同学写了下面的代码,你看看是否存在并发问题呢?

      

    1 void addIfNotExist(Vector v, 
    2     Object o){
    3   if(!v.contains(o)) {
    4     v.add(o);
    5   }
    6 }

      Vector实现线程安全是通过给主要的写方法加了synchronized,类似contains这样的读方法并没有synchronized,该题的问题就出在不是线程安全的contains方法,两个线程如果同时执行到if(!v.contains(o)) 是可以都通过的,这时就会执行两次add方法,重复添加。也就是老师说的竞态条件。

  • 相关阅读:
    redis 切换大量的缓存数据
    springboot jdbctemplate 常用的语法
    Spring Boot 整合 jdbctemplate 多数据源
    Spring Boot 整合 jdbctemplate 单数据源
    IDEA(Eclipse) 常用的快捷键(快速开发)
    bigdecimal 类型的变量怎么相互加减乘除
    在js和java中判断手机访问的是ios系统还是android系统
    fiddler抓web请求
    sign和token设计
    移动端自动化测试-Windows-Android-Appium环境搭建
  • 原文地址:https://www.cnblogs.com/woooodlin/p/13029030.html
Copyright © 2011-2022 走看看