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 线程安全和不可变性

    相关专题

    更多
    java
    java

    Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

    844

    2023.06.15

    java正则表达式语法
    java正则表达式语法

    java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

    743

    2023.07.05

    java自学难吗
    java自学难吗

    Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

    740

    2023.07.31

    java配置jdk环境变量
    java配置jdk环境变量

    Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

    397

    2023.08.01

    java保留两位小数
    java保留两位小数

    Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

    400

    2023.08.02

    java基本数据类型
    java基本数据类型

    java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

    447

    2023.08.02

    java有什么用
    java有什么用

    java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

    431

    2023.08.02

    java在线网站
    java在线网站

    Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

    16926

    2023.08.03

    c++空格相关教程合集
    c++空格相关教程合集

    本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

    0

    2026.01.23

    热门下载

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

    精品课程

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

    共28课时 | 4.8万人学习

    Excel 教程
    Excel 教程

    共162课时 | 13.2万人学习

    Kotlin 教程
    Kotlin 教程

    共23课时 | 2.8万人学习

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

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