0

0

JAVA并发编程总结:线程安全性、对象的共享

php是最好的语言

php是最好的语言

发布时间:2018-08-09 14:03:11

|

1708人浏览过

|

来源于php中文网

原创

第一章 简介

摘书

  1. 线程会共享进程范围内的资源,例如内存句柄和文件句柄,但每个线程都有各自的程序计数器(Program Counter)、栈以及局部变量等。

  2. 在同一个程序中的多个线程也可以被同时调度到多个CPU上运行。

第二章 线程安全性

摘书

  1. Java中的主要同步机制是关键字synchronized,它提供了一种独占的加锁方式,但“同步”这个术语还包括volatile类型的变量,显式锁(Explicit Lock)以及原子变量。

  2. 如果当多个线程访问同一个可变的状态变量时没有使用合适的同步,那么程序就会出现错误。有三种方式可以修复这个问题:

    立即学习Java免费学习笔记(深入)”;

  • 不在线程之间共享改状态变量。

  • 将状态变量修改为不可变的变量。

  • 在访问状态变量时使用同步。

  • 线程安全性定义:当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。

  • 无状态对象一定是线程安全的。

  • 大多数竞态条件的本质:基于一种可能失效的观察结果来做出判断或者是执行某个计算。这种类型的竞态条件成为“先检查后执行”:首先观察到某个条件为真(例如文件X不存在),然后根据这个观察结果采用相应的动作(创建文件X),但事实上,在你观察到这个结果以及开始创建文件之间,观察结果可能变得无效(另一个线程在这期间创建了文件X),从而导致了各种问题(未预期的异常、数据被覆盖、文件被破坏等)。

  • 假定有两个操作A和B,如果从执行A的线程来看,当另一个线程执行B时,要么将B全部执行完,要么完全不执行B,那么A和B对彼此来说是原子的。原子操作是指,对于访问同一个状态的所有操作(包括该操作本身)来说,这个操作是一个以原子方式执行的操作。

  • 在实际情况中,应尽可能地使用现有的线程安全对象(例如AtomicLong)来管理类的状态。与非线程安全的对象相比,判断线程安全对象的可能状态及其状态转换情况要更为容易,从而也更加容易维护和验证线程安全性。

  • 要保持状态的一致性,就需要在单个原子操作中更新所有相关的状态变量。

  • 重入的一种实现方法是,为每个锁关联一个获取计数值和一个所有者线程。当计数值为0时,这个锁就被认为是没有被任何线程持有。当线程请求一个未被持有的锁时,JVM将会记下锁的持有者,并且将获取计数值置为1。如果同一个线程再次获取这个锁,计数值将会递增,而当线程退出同步代码块时,计数器会相应地递减。当计数值为0时,这个锁将被释放。

  • 并非所有数据都需要锁的保护,只有被多个线程同时访问的可变数据才需要通过锁来保护。

  • 当执行时间较长的计算或者可能无法快速完成的操作时(例如,网络IO或控制台IO),一定不要持有锁。

  • 体会

    1. 状态的理解,我认为是类的成员变量。无状态对象就是成员变量不能储存数据,或者是可以储存数据但是这个数据不可变。无状态对象是线程安全的。如果方法中存在成员变量,就需要对这个成员变量进行相关的线程安全的操作。

    2. 不要一味地在方法前加synchronized,这可以保证线程安全,但是方法的并发功能会减弱,导致本来可以支持并发的方法变成堵塞,导致程序处理速度的变慢。

    3. synchronized包围的代码要尽可能的短,但是要保证有影响的所有成员变量在一起。没有关系的成员变量可以用多个synchronized包围。

    第三章 对象的共享

    摘书

    1. 加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步。

    2. Java语言提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程。当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重新排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。

    3. 在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比synchronized关键字更轻量级的同步机制。

    4. volatile变量通常用做某个操作完成、发生中断或者是状态的标志。volatile的语义不足以确保递增操作(count++)的原子性,除非你能确保只有一个线程对变量执行写操作。

    5. 加锁机制既可以确保可见性又可以确保原子性,而volatile变量只能确保可见性。

    6. 当且仅当满足以下所有条件时,才应该使用volatile变量:

    • 对变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。

    • 该变量不会与其他状态变量一起纳入不变形条件中。

    • 访问该变量时不需要加锁。

  • “发布(Publish)”一个对象的意思是指,使对象能够在当前作用域之外的代码中使用。

  • 当某个不应该发布的对象被发布时,这种情况就被称为逸出(Escape)。

  • 不要在构造过程中使this引出逸出。

  • 如果想在构造函数中注册一个事件监听器或者启动线程,那么可以使用一个私有的构造函数和一个公共的工厂方法(Factory Method),从而避免不正确的构造过程。

  • 栈封闭是线程封闭的一种特例,在栈封闭中,只有通过局部变量才能访问对象。

  • 维持线程封闭性的一种更规范方法是使用ThreadLocal,这个类能够使线程中的某个值与保存值的对象关联起来。

    点触小程序平台源码.NETCORE版本
    点触小程序平台源码.NETCORE版本

    点触小程序是有南昌点触科技有限公司研发,我公司是国家级高新技术企业,本套源码是国内首家应该到目前为止也是独家用.netcore开发的小程序平台站,公司有三个开发组同时做小程序平台开发,一个php开发组,一个java开发组,一个.netcore开发组,三组独立并行开发。目前投入上线运营的未php版本,其他两组均是做封闭性开发测试,不对外公布。秉着互联网的合作,共享,开放,共赢的原则,我们将本套.NE

    下载
  • ThreadLocal对象通常用于防止对可变的单实例对象(Singleton)或全局变量进行共享。

  • 当满足以下条件时,对象才是不可变的:

    • 对象创建以后其状态就不能修改。

    • 对象的所有域都是final类型。

    • 对象是正确创建的(在对象的创建期间,this引用没有逸出)。

  • 不可变对象一定是线程安全的。

  • 要安全地发布一个对象,对象的引用以及对象的状态必须同时对其他线程可见。一个正确构造的对象可以通过以下方式来安全地发布:

    • 在静态初始化函数中初始化一个对象引用。

    • 将对象的引用保存到volatile类型的域或者AtomicReferance对象中。

    • 将对象的引用保存到某个正确构造对象的final类型域中。

    • 将对象的引用保存到一个由锁保护的域中。

  • 在没有额外的同步的情况下,任何线程都可以安全地使用被安全发布的事实不可变对象。

  • 对象的发布需求取决于它的可变性:

    • 不可变对象可以通过任意机制来发布。

    • 事实不可变对象必须通过安全方式来发布。

    • 可变对象必须通过安全方式来发布,并且必须是线程安全的或者由某个锁保护起来。

  • 在并发程序中使用和共享对象时,可以使用一些实用的策略,包括:

    • 线程封闭。线程封闭的对象只能由一个线程拥有,对象被封闭在该线程中,并且只能由这个线程修改。

    • 只读共享。在没有额外同步的情况下,共享的只读对象可以由多个线程并发访问,但任何线程都不能修改它。共享的只读对象包括不可变对象和事实不可变对象。

    • 线程安全共享。线程安全的对象在其内部实现同步,因此多个线程可以通过对象的公有接口来进行访问而不需要进一步的同步。

    • 保护对象。被保护的对象只能通过持有特定的锁来访问。保护对象包括封装在其他线程安全对象中的对象,以及已发布的并且由某个特定锁保护的对象。

    体会

    1. 发布和逸出的理解:就是说一个类中的成员变量或者对象可以被其他的类所引用使用就是发布,如用static修饰的静态变量或者是当前调用方法的对象。逸出是指该成员变量或对象在本来不应该被多线程引用的情况下暴露出去被引用,导致其值可能被错误修改的问题。一句话,不要随便扩大一个类以及内部使用成员变量和方法的作用域。这也是封装应该考虑的问题。

    2. this逸出:即在构造方法的内部类中启动另一个线程引用了这个对象,但是这时这个对象还没有构造完成,可能会导致出乎意料的错误。解决方法是创建一个工厂方法,然后将构造器设置成私有构造器。

    3. final修改的成员变量需要在构造器在构造器中初始化,否则对象实例化后这个成员变量不能赋值。final修饰的成员变量是引用对象时,这个对象的地址不能修改,但是这个对象的值是可以修改的。

    4. 安全发布一个对象的四种方式的理解,如A类中有B类的引用:

    • A的静态初始化方法,如public static A a = new A(b);这样的静态工厂类中,引用B的时候初始化B。

    • A类中的B成员变量用volatile b或者是AtomicReferance b这样修饰。

    • A类中的B成员变量用final B b这样修饰。

    • A类中的方法使用到B的时候用synchronized(lock){B…}包围。

  • 事实不可变对象很简单的理解就是技术上是可变的,但是在业务逻辑处理中是不会去修改的对象。

  • 相关推荐:

    Java 线程全和共享资源

    java 线程安全和不可变性

    热门AI工具

    更多
    DeepSeek
    DeepSeek

    幻方量化公司旗下的开源大模型平台

    豆包大模型
    豆包大模型

    字节跳动自主研发的一系列大型语言模型

    通义千问
    通义千问

    阿里巴巴推出的全能AI助手

    腾讯元宝
    腾讯元宝

    腾讯混元平台推出的AI助手

    文心一言
    文心一言

    文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

    讯飞写作
    讯飞写作

    基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

    即梦AI
    即梦AI

    一站式AI创作平台,免费AI图片和视频生成。

    ChatGPT
    ChatGPT

    最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

    相关专题

    更多
    counta和count的区别
    counta和count的区别

    Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

    203

    2023.11.20

    全局变量怎么定义
    全局变量怎么定义

    本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

    93

    2025.09.18

    python 全局变量
    python 全局变量

    本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

    106

    2025.09.18

    c++中volatile关键字的作用
    c++中volatile关键字的作用

    本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

    75

    2025.10.23

    硬盘接口类型介绍
    硬盘接口类型介绍

    硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

    1923

    2023.10.19

    PHP接口编写教程
    PHP接口编写教程

    本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

    656

    2025.10.17

    php8.4实现接口限流的教程
    php8.4实现接口限流的教程

    PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

    2392

    2025.12.29

    java接口相关教程
    java接口相关教程

    本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

    47

    2026.01.19

    C# ASP.NET Core微服务架构与API网关实践
    C# ASP.NET Core微服务架构与API网关实践

    本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

    3

    2026.03.11

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    Rust 教程
    Rust 教程

    共28课时 | 6.8万人学习

    Excel 教程
    Excel 教程

    共162课时 | 21万人学习

    Kotlin 教程
    Kotlin 教程

    共23课时 | 4.3万人学习

    关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
    php中文网:公益在线php培训,帮助PHP学习者快速成长!
    关注服务号 技术交流群
    PHP中文网订阅号
    每天精选资源文章推送

    Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号