本文转载自微信公众号《老胡爱分享》,作者hoohack。转载本文请联系老胡爱分享公众号。如果面试官问你,线程安全类有哪些,什么是线程安全?你怎么回答?我们整天都在谈论线程安全,但是你真的了解什么是线程安全吗?从学术上理解什么是进程,一个进程就是程序执行时间的总和包括上下文切换=CPU加载上下文+CPU执行+CPU保存上下文。另一个简单的理解就是进程就是程序的一次执行。比如你看这张图,每一个运行的程序都是一个独立的进程,进程之间是相互独立存在的。什么是线程线程是CPU执行部分的一小段,线程是CPU的基本调度单位。注意:通常人们会说“因为Redis是单线程的,所以它是原子的”。根本原因是因为线程是CPU的最小调度单位,CPU只能在每次执行成功或失败时调度切换到下一个线程,所以Redis操作是原子的。进程和线程都是对一个时间段的描述,是对CPU工作时间段的描述,只是粒度不同而已。堆和栈进程和线程中比较重要的内存区域是堆和栈。堆是进程和线程共享的空间,分为全局堆和局部堆。全局堆都是未分配的空间,局部堆是用户分配的空间。堆是在操作系统初始化进程时分配的。在运行过程中,也可以向系统请求额外的heap,但是用完一定要归还给操作系统,否则会造成内存泄漏。在Java中,堆是Java虚拟机管理的最大一块内存。它是所有线程共享的内存区域,在虚拟机启动时创建。堆所在的内存区域的唯一目的就是存放对象实例,几乎所有的对象实例和数组都在这里分配内存。堆栈对于每个线程都是唯一的,保存着它的运行状态和局部自动变量。栈在线程启动时初始化,每个线程的栈相互独立。因此,堆栈是线程安全的。操作系统在切换线程时会自动切换堆栈。堆栈空间不需要在高级语言中显式分配和释放。几乎所有进程和线程中的数据程序都需要和数据打交道,读数据(命令行参数,文件),写数据(设置变量,写文件)。这些数据存储在进程管理的内存中。为了保证数据的安全,比如一个进程修改的数据不会影响到另一个进程的数据,每个进程都会有自己的内存空间,由操作系统分配,不能访问其他进程的数据,这是由保证的操作系统决定的。进程占用的资源:地址空间、全局变量、打开的文件、子进程、信号量、账户信息线程占用的资源:栈、寄存器、状态、程序计数器系统。资源不共享,通过进程间通信共享资源,而线程可以共享部分资源,单独拥有的资源不共享。线程间共享的数据包括:1.堆2.进程代码段3.进程的公共数据对于线程间共享的内存区域,如果进程中的线程A操作数据,则切换到线程B执行并修改相同的数据,返回到线程A时,数据不是线程A切换时的数据。这样,数据就会被污染。我们说这段数据在多线程环境下是不安全的,也就是线程不安全。这就是线程安全概念产生的背景。笔者认为,谈到线程安全,首先要介绍一下操作系统和线程中操作内存的过程。不然说一个对象安全不安全,就有点唐突了。并且不知道相对于什么是安全的。线程安全《Java并发编程实战》给出了如下定义:一个对象是否需要线程安全取决于它是否被多线程访问。这只与对象在程序中的使用方式有关,与对象本身做什么无关。如果一个类在被多个线程访问时始终表现正确,则称该类是线程安全的。线程安全的程序不一定由线程安全的类组成,完全由线程安全的类组成的程序也不一定是线程安全的。还需要一定的组合技巧来确保线程安全。编写线程安全的代码,核心是管理对象状态的访问操作,特别是共享(Shared)和可变(Mutable)状态的访问,即数据的访问,而数据是存储在内存中的,也就是说,线程安全的本质不是代码在线程中的安全,而是内存在线程中的安全。至此,线程安全的概念就介绍完了。最后,你知道有哪些方法可以保证线程安全吗?总结分享一个学习方法,带着问题看书。有时候从头到尾读一本书真的很无聊,很容易放弃。最近想了一个带着问题看的方法,比如?,据说是Java并发编程的神书,但是很枯燥,而且中文版的也很难看懂。看了好几遍都进不去状态。然后我就想,能不能去网上看看一些面试题,看看这本书能帮我解答哪些疑惑。我只读了前三章。如果带着问题去看,会更有目的性,也更容易理解,再用自己的语言描述一下,印象会更深。
