1. 线程安全

线程安全是编程中的术语,指某个函数、函数库在并发环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成

1.1. 并发

并发(Concurrent)

在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行.在单CPU的计算机中,我们看起来“同时干多件事”,其实是通过CPU时间片技术,并发完成的.

并行(Parallel)

当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

并发与并行的区别

可以这样理解:并发是两个队伍交替使用一台咖啡机。并行是两个队伍同时使用两台咖啡机。
映射到计算机系统中,咖啡机就是CPU,两个队伍指的就是两个进程

1.2 多线程

进程和线程

在上下文切换过程中,CPU会停止处理当前运行的程序,并保存当前程序运行的具体位置以便之后继续运行。从这个角度来看,上下文切换有点像我们同时阅读几本书,在来回切换书本的同时我们需要记住每本书当前读到的页码。在程序中,上下文切换过程中的“页码”信息是保存在进程控制块(PCB)中的。PCB还经常被称作“切换帧”(switchframe)。“页码”信息会一直保存到CPU的内存中,直到他们被再次使用。

对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。
而在多个进程之间切换的时候,需要进行上下文切换。但是上下文切换势必会耗费一些资源。于是人们考虑,能不能在一个进程中增加一些“子任务”,这样减少上下文切换的成本。比如我们使用Word的时候,它可以同时进行打字、拼写检查、字数统计等,这些子任务之间共用同一个进程资源,但是他们之间的切换不需要进行上下文切换。
在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。
随着时间的慢慢发展,人们进一步的切分了进程和线程之间的职责。把进程当做资源分配的基本单元,把线程当做执行的基本单元,同一个进程的多个线程之间共享资源。

1.3 共享变量

前面我们提到过,进程视分配资源的基本单位,线程是执行的基本单位。所以,多个线程之间是可以共享一部分进程中的数据的。在JVM中,Java堆和方法区的区域是多个线程共享的数据区域。也就是说,多个线程可以操作保存在堆或者方法区中的同一个数据。那么,换句话说,保存在堆和方法区中的变量就是Java中的共享变量。
Java中共有三种变量,分别是类变量、成员变量和局部变量。他们分别存放在JVM的方法区、堆内存和栈内存中。

  1. public class Variables {
  2. /**
  3. * 类变量
  4. */
  5. private static int a;
  6. /**
  7. * 成员变量
  8. */
  9. private int b;
  10. /**
  11. * 局部变量
  12. * @param c
  13. */
  14. public void test(int c){
  15. int d;
  16. }
  17. }

上面定义的三个变量中,变量a就是类变量,变量b就是成员变量,而变量c和d是局部变量。
所以,变量a和b是共享变量,变量c和d是非共享变量。所以如果遇到多线程场景,对于变量a和b的操作是需要考虑线程安全的,而对于线程c和d的操作是不需要考虑线程安全的。
定义中说线程安全能够正确地处理多个线程之间的共享变量,使程序功能正确完成