画布 1
Chapter13.线程安全与锁优化
  线程安全
    定义：当多个线程访问一个对象时，如果不用考虑这些线程在运行时环境下的调度和交替执行，也不需要进行额外的同步，或者在调用方进行任何其他的协调操作，调用这个对象的行为都可以获得正确的结果，那这个对象就是线程安全的。
    不可变
      不可变的对象一定是线程安全的
    绝对线程安全
      绝对的线程安全完全满足线程安全的定义
    相对线程安全
      相对线程安全就是我们通常意义上所讲的线程安全，它需要保证对这个对象的单独操作是线程安全的，我们在调用的时候不需要做额外的保障措施，但是对于一些特定顺序的连续调用，就可能需要在调用端使用额外的同步手段来保证调用的正确性。在Java语言中，大部分的线程安全类都属于这种类型，列如Vector、HashTable、Collections的synchronizedCollection()方法包装的集合等。
    线程兼容
      指对象本身不是线程安全的，但是可以通过在调用端正确的使用同步手段来保证对象在并发环境中可以安全的使用，我们平常说一个类不是线程安全的，绝大多数时候指的是这一种情况。
    线程对立
      指无论调用端是否采取了同步措施，都无法在多线程环境中并发使用的代码。一个线程对立的列子就是Thread类的suspend()和resume()方法
  线程安全实现方法
    互斥同步
      互斥同步最主要的问题就是进行线程阻塞和唤醒所带来的性能问题
      互斥同步属于一种悲观的并发策略，总是认为只要不去做正确的同步措施（例如加锁）.无论共享数据是否真的会出现竞争，它都要进行加锁、用户态核心态转换、维护锁计数器和检查是否有被阻塞的线程需要唤醒等操作
      典型：悲观加锁
    非阻塞同步
      基于冲突检测的乐观并发策略，通俗地说，就是先进行操作，如果没有其他线程争用共享数据，那操作就成功了；如果共享数据有争用，产生了冲突，那就再采取其他的补偿措施（最常见的补偿措施就是不断地重试，直到成功为止），这种乐观的并发策略的许多实现都不需要把线程挂起，因此这种同步操作称为非阻塞同步（Non-Blocking Synchronization）
      典型：乐观CAS
    无同步方案
      （1）可重入代码（Reentrant Code）：这种代码也叫做纯代码（Pure Code），可以在代码执行的任何时刻中断它，转而去执行另外一段代码（包括递归调用它本身），而在控制权返回后，原来的程序不会出现任何错误
      （2）线程本地存储（Thread Local Storage）：java.lang.ThreadLocal类实现了线程本地存储的功能。每一个线程的Thread对象中都有一个ThreadLocalMap对象，使用这个值就可以在线程K-V值对中找回对应的本地线程变量。
      典型：函数式编程
  互斥实现的主要方式
    临界区（Critical Section）：通过对多线程的串行化来访问公共资源或一段代码，速度快，适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问，如果有多个线程试图访问公共资源，那么在有一个线程进入后，其他试图访问公共资源的线程将被挂起，并一直等到进入临界区的线程离开，临界区在被释放后，其他线程才可以抢占。
    互斥量（Mutex）：采用互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限，因为互斥对象只有一个，所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享，还能实现不同应用程序的公共资源安全共享。
    信号量（Semaphore）：与临界区和互斥量不同，可以实现多个线程同时访问公共区域数据，先设置一个访问公共区域的线程最大连接数，每有一个线程访问共享区资源数就减一，直到资源数小于等于零。
    事件（Event）：通过通知操作的方式来保持线程的同步，还可以方便实现对多个线程的优先级比较的操作
  锁优化
    自旋锁与自适应自旋
      如果物理机器有一个以上的处理器，能让两个或以上的线程同时并行执行，我们就可以让后面请求锁的那个线程“稍等一下”，但不放弃处理器的执行时间，看看持有锁的线程是否很快就会释放锁。为了让线程等待，我们只需让线程执行一个忙循环（自旋），这项技术就是所谓的自旋锁。
    锁消除
      指虚拟机即时编译器在运行时，对一些代码上要求同步，但是被检测到不可能存在共享数据竞争的锁进行消除。锁消除的主要判定依据来源于逃逸分析的数据支持，如果判断在一段代码中，堆上的所有数据都不会逃逸出去从而被其他线程访问到，那就可以把它们当做栈上数据对待，认为它们是线程私有的，同步加锁自然就无须进行。
    锁粗化
      如果一系列的连续操作都对同一个对象反复加锁和解锁，甚至加锁操作是出现在循环体中的，那即使没有线程竞争，频繁地进行互斥同步操作也会导致不必要的性能损耗。如果虚拟机探测到有这样一串零碎的操作都对同一个对象加锁，将会把加锁同步的范围扩展（粗化）到整个操作序列的外部，如StringBuffer的多次append()操作，扩展到第一个append（）操作之前直至最后一个append（）操作之后，这样只需要加锁一次就可以了。
    轻量级锁
      轻量级锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量，轻量级锁并不是用来代替重量级锁的，它的本意是在没有多线程竞争的前提下，减少传统的重量级锁使用操作系统互斥量产生的性能消耗。
    偏向锁
      它的目的是消除数据在无竞争情况下的同步原语，进一步提高程序的运行性能。如果说轻量级锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量，那偏向锁就是在无竞争的情况下把整个同步都消除掉，连CAS操作都不做了。偏向锁会偏向于第一个获得它的线程，如果在接下来的执行过程中，该锁没有被其他的线程获取，则持有偏向锁的线程将永远不需要再进行同步。
        例子：synchronized