zoukankan      html  css  js  c++  java
  • 如何回答什么是线程安全?

    前言

    在面试过程中,很多的面试官都喜欢开局先来一个说一下你对线程安全的认识。这个问题呢广度挺大的,不同人理解不同,回答不同。如果不能好好的接下这一招,那么面试官就可能对你们后面的期待大大减小。

    秋招在即,根据个人的见解和所查资料,对这一招进行拆招。(不一定是好招,仅为个人总结)

    概念

    首先呢,肯定要快速介绍一下线程安全。所谓的线程安全,就是在当多个线程同时访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那么就称这个对象是线程安全的。

    简单来说,就是在多线程下执行某个类,该对象始终都能保持正确的行为。

    Java中的线程安全

    在这里呢,如果有时间(面试官没打断)就跟可以面试官聊聊在Java中线程安全的安全划分层次。如果面试官直接问你那怎么保证线程安全呢,那就直接跳到下一个问题的答案。

    在Java中根据线程的“安全强度”可以由强至弱来排序分别分为五类:不可变、绝对线程安全、相对线程安全、线程兼容和线程独立。(该部分摘录自参考资料书籍)

    不可变

    我们说过所谓线程安全在就是在多线程下执行,还能够始终保持正确的行为。而我们的不可变的对象一定是线程安全的,无论是对象的方法实现还是方法的调用者,都不需要再进行任何线程安全保障措施。

    这个不可变其实很好理解,一旦我们的一个不可变对象被正确被构建出来(即没有发生this引用逃逸的情况),那其外部的可见性永远都不会改变的,永远都不会看到它在多个线程之中处于不一致的状态。

    Java中,如果是多线程共享变量是一个基本数据类型可以使用final关键字来修饰,就可以保证不可变。如果共享数据是一个对象的话,只能让对象自己保证其行为不会其状态产生任何影响才行。比如String,用户调用substring(),replace()和concat()这些方法都不会影响它原来的值,只会返回一个新构造的字符串对象。保证对象行为不影响状态的途径有很多,一个比较有效的就是将带有状态变量的变量声明为final。(如Java中Integer类等)

    绝对线程安全

    绝对线程安全是比较严格的,它的定义是“不管运行时环境如何,调用者都不需要任何额外的同步措施。”例如我们的Vector就是一个线程安全容器,底层的方法也通过Synchronized来修饰,具备了原子性、可见性、有序性。但是它就不是一个绝对线程安全的,可以考虑这样一个特殊情况:

    在多线程下,我们的一个线程恰好在错误的时间里面删除了一个元素,位置为i,那么另一个线程就有可能访问到这个i的时候发生数组越界异常。而我们的Vector要做到绝对的线程安全,就必须在它内部维护一组一致性的快照访问才行,每次对其中元素进行改动都要产生新的快照,但是时间和空间成本大。

    相对线程安全

    相对线程安全就是我们通常所说的线程安全,它保证对这个对象单次的操作是线程安全的,我们在调用的时候不需要进行额外的保证措施。在Java中,大部分声称线程安全的类都属于这种类型,例如Vector、HashTable、Collections的synchronizedCollection()方法包装的集合等。

    线程兼容

    线程兼容是指对象本身并不是线程安全的,但是可以通过在调用端正确地使用同步手段来保证对象在并发环境中可以安全地使用。我们平常说一个类不是线程安全的,通常就是指这种情况。Java类库API中大部分的类都是线程兼容的,如与前面的Vector和HashTable相对应的集合类ArrayList和HashMap等。

    线程对立

    线程对立是指不管调用端是否采取了同步措施,都无法在多线程环境中并发使用代码。

    一个线程对立的例子是Thread类的suspend()和resume()方法。如果有两个线程同时持有一个线程对象,一个尝试去中断线程,一个尝试去恢复线程,在并发进行的情况下,无论调用时是否进行了同步,目标线程都存在死锁风险。

    解决线程安全问题

    线程安全也可以说是一类问题。因为只要我们用到多线程,就肯定需要考虑到线程安全的问题。所以我们针对线程安全问题有以下的方式去解决它。

    线程安全实现方式

    方式一:

    核心思路是避免共享数据结构,共享状态。包括:

    (1)使用线程local变量

    (2)使用不可变对象

    方式二:

    核心思路是共享不可避免,需要通过条件来确保按照。包括:

    (1)互斥锁(互斥同步)

    (2)CAS原子操作(非阻塞同步)

    Java中实现策略

    (1)ThreadLocal变量,Volatile变量

    (2)不可变对象有String,CopyOnWrite集合类

    (3) 内置锁synchronized和Lock接口下是实现锁

    (4) JUC下的原子类

    参考资料

    深入理解Java虚拟机第三版

    如何理解什么是线程安全?

  • 相关阅读:
    匿名内部类
    父类引用指向子类对象【转】
    书签收集
    Linux搭建我的世界服务器
    Python入门学习-DAY27- isinstance与issubclass、反射、内置方法
    Python入门学习-DAY26-绑定方法与非绑定方法
    Python入门学习-DAY25-组合、多态、封装
    Python入门学习-DAY24-继承
    Python入门学习-DAY23-面向对象编程
    Python入门学习-DAY20-常用模块三-re模块、subprocess模块
  • 原文地址:https://www.cnblogs.com/CryFace/p/13618538.html
Copyright © 2011-2022 走看看