浅谈线程安全

背景

当我们编写double check 单例的时候,如果使用pmd等静态代码检测工具检测的时候,会报线程不安全的错误。

比如我们定义一个单例类:

public final class SingleTest { private static SingleTest sSingleTest; private SingleTest() { } public static SingleTest getInstance() { if (sSingleTest == null) { synchronized (SingleTest.class) { if (sSingleTest == null) { sSingleTest = new SingleTest(); } } } return sSingleTest; }

} 

执行pmd任务(如何执行pmd任务大家自行Google,网上一大堆),输出报告如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<pmd xmlns="http://pmd.sourceforge.net/report/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/report/2.0.0 http://pmd.sourceforge.net/report_2_0_0.xsd" version="6.8.0" timestamp="2021-08-21T17:37:47.921">
<file name="/Users/liuwei/AndroidStudioProjects/MyTestApplication/app/src/main/java/com/pplovely/mytestapplication/SingleTest.java">
<violation beginline="13" endline="19" begincolumn="9" endcolumn="9" rule="NonThreadSafeSingleton" ruleset="Multithreading" package="com.pplovely.mytestapplication" class="SingleTest" method="getInstance" externalInfoUrl="https://pmd.github.io/pmd-6.8.0/pmd_rules_java_multithreading.html#nonthreadsafesingleton" priority="3">
Singleton is not thread safe
</violation>
</file>
</pmd> 

这里很明显提示 “Singleton is not thread safe”

这是什么原因呢?明明都是通过同步锁来操作了,还不能保证线程安全吗?

通过这篇文章来简要的说明线程安全相关的概念。

线程基础

线程(Thread),是程序执行流的最小单元。 一个标准的线程由线程ID、当前指令指针、寄存器集合和堆栈组成。通常意义上,一个进程由一个到多个线程组成,各个线程之间共享程序的内存空间(包括代码段、数据段、堆等)及一些进程级的资源(如打开文件和信号)。

一般进程和线程的关系图如下:

多个线程可以互不干扰的并发执行,并共享进程的全局变量和堆的数据。那么多个线程与单线程的进程相比,有哪些优势呢?通常来说,使用多线程的原因有如下几点:

  • 某个操作会消耗大量的时间(通常都是计算),如果只有一个线程,程序和用户之间的交互就会中断。多线程可以让一个线程负责交互,另一个线程负责计算。
  • 程序逻辑本身就要求并发操作。比如商店的多端下载功能
  • 多CPU和多核设备本身就支持同时执行多个线程的能力,因此单线程程序无法全面发挥计算机的全部计算能力
  • 相对多进程应用,多线程在数据共享方面效率要高很多

线程的访问权限

线程也拥有属于自己的私有存储空间,包括:

  • 线程局部存储(Thread Local Storage,TLS)。线程局部存储是某些操作系统为线程单独提供的私有空间,但通常只是具有很有限的容量
  • 寄存器,寄存器是执行流的基本数据,因此为线程私有

从C程序员的角度来看,数据在线程之间是否私有如下表格所示:

线程私有 线程之间共享(进程所有)
局部变量 全局变量
函数的参数 堆上的数据
TLS数据 函数里的静态变量
程序代码,任何线程都有权利读取并执行任何代码
打开的文件,A线程打开的文件可以由B线程读写

线程的调度与优先级

当线程的数量小于等于处理器数量(包括多核处理器),线程的并发是真正的并发,不同的线程运行在不同的处理器上,彼此之间互不干扰。但是对于线程数量大于处理器器数量的情况,线程的并发就会受到一些阻碍,因此此时至少有一个处理器会运行多个线程。

在单处理器(假设单核)对应多线程的情况下,并发是一种模拟出来的状态。操作系统会让这些多线程程序轮流执行,每次执行一小段时间(通常是几十到几百毫秒),这样每个线程就“看起来”在同时执行。这样的一个不断在处理器上切换不同的线程的行为称之为线程调度(Thread Schedule)

在线程调度中,线程通常拥有至少三种状态,分别是&#x

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值