线程安全,这词你懂了吗?

前言

还记得你第一次遇到「线程安全」这个词的时候吗?

我第一次遇到线程安全这个词是在学习多线程并发操作的时候,看到人家文章里出现这个词,还有说各种线程安全的类,但是一开始并不理解线程安全是什么意思,也没去深究线程怎样是安全的?怎样是不安全的?只是脑子里接收了这么一个词。

线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。——《百度百科》

默认已学前置知识

  • 进程:程序的一次执行的过程,是动态的,是系统进行资源分配的基本单位。一个进程里可以有多个线程。
  • 线程:是一个系统进行调度的基本单位,是能独立运行的。

下面开始回炉重造!打好基础!

线程安不安全是怎样定义的?

先给出个问题,为什么有线程安全这个词?这个词是怎么来的?可能这里会有点懵,不过没事,我来回答。

在多线程的情况下,我们会遇到这样一个问题,这里举例 A、B、C 三个线程,它们共同操作同一个资源(呐,这里同一个资源指的是,变量,方法这些,更准确的话,应该说是内存,毕竟值都是存储内存中的)。记住,前提是多线程,毕竟如果你单线程,就不可能不安全了,单线程直接安安全全!

A、B、C并发执行

这三个线程同时操作,就可能出现这样的问题,比如举个具体的例子,经典例子,买票(老演员了)!啥票都行。

三个线程代表三个人,票的剩余量对于这三个线程来说就是共享资源。

设票的剩余量为10,记 ticketSurplus = 10。三人购票,那么肯定需要对这个剩余量进行减一操作的。

public void buy() {
    ticketSurplus = ticketSurplus - 1;
    System.out.println(ticketSurplus);
}

那么现在同时执行,就很大可能会出现这样的情况,如图所示(假设这三个线程执行顺序是A、B、C,实际上顺序是不确定的):

执行过程出现的问题

从上面可以看出,输出结果为:9,9,8,而从上帝视角来看,显然是错误的,因为两个人买了票,不能只减一张票的值,正确的结果应该为9,8,7

所以,在多线程并发的情况下,这就是所谓的「不安全」,即不能正确执行,结果出现了混乱(数据污染)。

线程安全?

所谓线程安全,就是指当并发情况下,也就是有多个线程操作同一个资源(具体的话,这里同一个资源可以看成上面例子中的 ticketSurplus,当然这个同一资源也不一定只的是一个变量,也可以是某一个方法),能不能保证这个资源的一致性,如果任何时候都能够保证这种正确的操作结果,那么就可以说是线程安全的。

如何保证线程安全?

在学习操作系统的时候,我们学习了进程管理的内容,其中就有个「进程同步」的概念,所谓进程同步,说简单点就是进程之间具有前后的执行关系。在并发的情况下,不同进程有不同制约关系,比如某些情况下我们是需要 A 进程先执行,然后 B 进程再执行的,但是操作系统具有「异步性」,在并发的情况下,可能出现 B 先执行,A 后执行了,这显然不是我们想要的,所以如果不制约,不控制进程的同步,就会出现上面说的情况。

当然,除了「同步」这个词,还有一个词——「互斥」,互斥也是用于控制进程之间关系的。

同步:完成某种任务,需要进程之间的执行顺序有先后顺序,相互协调工作。

互斥:一个进程进入临界区访问临界资源,那么剩下的进程就需要进行等待,只有当它退出临界区,才允许下一个进程访问。

在 Java 中,我们可以通过 synchronized 关键字来保证临界区的同步互斥,当然还有其他的锁也可以实现同步互斥,进而保证多线程运行的安全。

总的来说,在多线程的情况下,通过加锁的方式保证线程安全。

最后的最后

由本人水平所限,难免有错误以及不足之处, 屏幕前的靓仔靓女们 如有发现,恳请指出!

最后,谢谢你看到这里,谢谢你认真对待我的努力,希望这篇博客对你有所帮助!

你轻轻地点了个赞,那将在我的心里世界增添一颗明亮而耀眼的星!