• 并发基础知识 — 线程安全性


      前段时间看完了《并发编程的艺术》,总感觉自己对于并发缺少一些整体的认识。今天借助《Java并发编程实践》,从一些基本概念开始,重新整理一下自己学过并发编程。从并发基础开始,深入进去,系统学习一下并发编程。

      编写线程安全的代码,核心在于要对状态访问操作进行管理,特别是对共享的(Shared)和可变的(Mutable)状态的访问。对象的状态是指存储在状态变量(实例或静态域)中的数据。对象的状态还可能包括其他依赖对象的域。(Map.Entry)

      一个对象是否需要时线程安全的,取决于该对象是否被多线程访问。这指的是程序中访问对象的方式,而不是对象要实现的功能。要使得对象是线程安全的,要采用同步机制来协同对对象可变状态的访问。Java常用的同步机制是Synchronized还包括 volatile类型的变量,显示锁以及原子变量

      线程安全的程序是否完全由线程安全的类构成?答案是否定的,完全由线程安全的类构成的程序并不一定是线程安全的,线程安全类中也可以包含非线程安全的类。只有当类中仅包含自己的状态时,线程安全类才有意义!

    什么是线程安全性?

      当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么这个类就是线程安全的。

      正确性:某个类的行为与其规范相一致。(我理解的规范就是我们在编写类时,能预知的状态结果)

    原子性

      竞态条件(Race Condition):某个计算的正确性取决于多个线程的交替执行的时序。(线程的时序不同,产生的结果可能会不同)

      “先检查后执行”,即通过一个可能失效的观测结果来决定下一步的操作。

      首先观察到某个条件为真,然后开始执行相关的程序,但是在多线程的运行环境中,条件判断的结果以及开始执行程序中间,观察结果可能变得无效(另外一个线程在此期间执行了相关的动作),从而导致无效。常见的就是(Lazy Singleton)

     1 /**
     2  * describe: 懒汉式单例模式
     3  *     优点:只有在需要使用LazySingleton1对象时,才真正生成一个LazySingleton1对象
     4  *     缺点:会因为某些Java 平台内存模型允许无序写入,使得getInstance方法可能返回
     5  *           一个尚未执行构造函数的对象
     6  * Created by tianc on 2017/4/15.
     7  */
     8 public class LazySingleton {
     9     private static LazySingleton lazyInstance = null;
    10     private LazySingleton() {
    11     }
    12     public static LazySingleton getInstance(){
    13         if(lazyInstance == null){
    14             synchronized (LazySingleton.class){
    15                 if(lazyInstance == null){
    16                     lazyInstance = new LazySingleton();
    17                 }
    18             }
    19         }
    20         return lazyInstance;
    21     }
    22 }
    LazySingleton

      “读取-修改-写入”,基于对象之前的状态来定义对象状态的转换。即使是volatile修饰的变量,在多线程的环境里面进行自增操作,同样会发生竞态条件,所以volatile不能保证绝对的线程安全(360面试问题)。

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

    加锁机制

      线程安全的定义中,多个线程间的操作无论采用何种执行时序或交替方式,都要保证不变性条件不被破坏。当不变性条件中涉及多个变量时,各个变量之间并不是互相独立的,一个变量发生变化会对其他变量的值产生约束。因此,一个变量发生改变,在同一个原子操作里面,其他相关变量也要更新。

      内置锁:同步代码块(Synchronized Block)包括两部分:一个作为锁的对象引用,一个作为由这个锁保护的代码块。关键字Synchronized修饰方法就是一种同步代码块,锁就是方法调用所在的对象,静态的Synchronized方法以Class对象作为锁。内置锁或监视锁就是以对象作为实现同步的锁

      Java内置锁,进入的唯一途径是执行进入由锁保护的同步代码块或方法。它相当于一种互斥锁。

      重入锁:当一个持有锁的线程再次请求进入自己持有的锁时,该请求会成功。"重入"意味着获取锁的操作的粒度是“线程”,而不是“调用”。重入的一种实现方式,为每个锁关联一个计数器和线程持有者。

    用锁来保护状态

      由于锁能使其保护的代码路径以串行形式访问,因此可以通过锁来构造一些协议以实现对共享状态的独占访问。

      对象的内置锁与其状态之间没有内在的联系,虽然大多数类都将内置锁用做一种有效的加锁机制,但对象的域并不一定要通过内置锁来保护。

      对于每个包含多个变量的不变性条件,其中涉及的所有变量都要使用同一个锁来保护/同步。

  • 相关阅读:
    电话线路使用的带通虑波器的宽带为3KHz (300~3300Hz),根据奈奎斯特采样定理,最小采样频率应为(16)。
    总线宽度为32bit,时钟频率为200MHz,若总线上每5个时钟周期传送一个32bit的字,则该总线的带宽为 (4) MB/S。
    安全需求可划分为物理安全、网络安全、系统安全和应用安全,下面的安全需求中属于系统安全的是(67),属于应用安全的是(68)。
    IP地址202.117.17.254/22是什么地址?
    公司的到一个B类地址块,需要划分成若干个包含1000台主机的子网,则可以划分成几个?
    PGP(Pretty Good Privacy)是一种电子邮件加密软件包,它提供数据加密和数字签名两种服务,采用(42)进行身份认证,使用(43) (128位密钥)进行数据加密,使用(44)进行数据完整性验证。 A.RSA公钥证书 B.RSA私钥证书 C.Kerboros证书 D.DES私钥证书
    comet反向Ajax模型原理与模型(笔记一)
    EasyARM-iMX257_U-Boot源代码移植分析
    linux移植u-boot(一)——U-Boot详解+自定义命令实战
    Ajax实现大文件切割上传
  • 原文地址:https://www.cnblogs.com/tcming/p/6711506.html
Copyright © 2020-2023  润新知