Java多线程——多线程相关知识的逻辑关系梳理

1 学习多线程知识的根本目标

       多线程知识的根本目标是:设计稳健的并发程序。
       固然,本文没法回答这个实践性很强的问题(这与具体的业务相关,涉及到具体的策略),本文主要阐述相关知识之间的关系,但愿初学者不要迷失在多线程工具类的API接口中。缓存

2 并发程序的三大宏观问题

       线程安全性问题、性能问题、活跃性问题。 三者的关系是,在设计并发程序过程当中要首先保证线程安全,在线程安全的基础上努力提高程序性能,在保证线程安全与提高性能时避免引入活跃性问题。
       线程安全是最重要的,设计并发程序是为了提高程序的性能,可是永远不要忘记性能是创建在安全的基础上的;而在保证安全性(如加锁、同步等方法)及优化并发性能(如经过锁分解、锁分段等方法)过程当中,可能会引入活跃性问题(如死锁、饥饿、活锁、糟糕的响应性等问题)。 本文主要阐述线程安全问题的知识。安全

3 线程安全性

3.1 线程安全性的定义

       当多个线程访问某个类时,这个类始终都能表现出正确行为,那么就称这个类是线程安全的。最核心的概念就是正确性。正确性的含义是,某个类的行为与其规范彻底一致。
       就像你要设计一道菜,那么组成这道菜的食材和调料必定是可控的,即你能确切的描述对这些食材和调料操做的结果,好比放油菜会香,放盐菜会咸,而且知道菜快熟时再放盐,只有对构成这道菜的全部元素都清楚明晰,设计出的菜才符合设想。设计程序时也同样,只有使用的各个变量和函数是可控的,设计出的程序才能按照设计运行。而多线程的使用,可能会使得组成程序的某些变量和行为变得不可控多线程

3.2 为何多线程会带来线程安全性问题

       要阐明线程安全性问题须要深刻到JAVA内存模型,这里暂时不引入,这里用两个生活中的例子来阐述线程安全性问题的本质(原子性问题和可见性问题)。
例1】以炒菜为例。其中有个操做是放盐,放盐的操做可分解为三个步骤“找到盐罐→检查盐罐装的是盐→菜快熟的时候将盐倒入菜中”。若是只有一我的在使用盐罐,那么不会有什么问题。可是,若是在你“检查盐罐中装的是盐”以后,将盐倒入菜中以前,另外一我的拿走了盐罐,装了三氯氰胺奶粉,而后将盐罐放回。这个调换过程你并不知道,最后你将调换过的三氯氰胺奶粉倒入了菜中,结果可想而知。这就是线程安全性问题的原子性问题
从内存模型理解原子性问题juejin.im/post/5d7760…并发

例2】以A和B协做煮米饭为例。有三个房间(厨房、控火室、观察室),厨房有个锅煮着米饭(锅上有张纸写着“已熟”或者“未熟”),A在控火室负责关火(当看到锅上的纸写着“已熟”时关火),B在观察室负责观察米的状态并修改锅上贴纸的状态字(已熟/未熟);A和B不在一个房间,没法直接交流;B隔一会观察下锅里的米,若是米熟了就在一张纸上写“已熟”,未熟就写“未熟”,B很忙,写完字后将纸贴在了本身门上,未贴在厨房的锅上。最终结果是,A看到锅上的状态字一直是“未熟”,因此不关火,最终米饭糊了。这就是可见性问题
从内存模型理解可见性问题juejin.im/post/5d7760…函数

3.3 解决原子性问题和内存可见性的核心

       要编写线程安全的代码,其核心在于要对状态(变量)访问操做进行管理,特别是对共享的可变的状态的访问。
       共享意味着可由多个线程访问操做,可变意味着能够被修改。
       上述例1中,若是盐罐不共享即其余人不能使用,则不会有线程安全性问题。若是规定不能往盐罐中装入,只能从盐罐中取出,那么无论多少我的能够操做盐罐,盐罐中始终是盐,没有线程安全性问题;一样,若是一个变量不能被修改,那么无论多少个线程操做这个变量,也不会带来线程安全性问题。
       上述例2中,若是强制B在修改状态字后,将纸贴在锅上,那么就可让A看到米饭的真正状态,就能够及时关掉火,蒸出香喷喷的米饭。工具

       那么,为了解决原子性问题和内存可见性问题,怎么对共享的且可变的变量进行管理?post

  • 除非须要某个域是可变的,不然应将其声明为final域(即声明为不可变的)
  • 将对共享变量的并行操做转换为串行操做(如同步机制、将变量委托给同步容器进行管理)
  • 将共享变量转换为不共享变量(如线程封闭(栈封闭、ThreadLocal类等))
  • 若是某个操做须要以原子方式执行,那么就想办法保证这个操做是原子方式执行(如给操做加锁)
  • 对于须要保证内存可见性的变量,能够强制线程从主内存而不是缓存中读取变量,在线程存储变量时强制存取到主内存中。(如加锁,声明volatile变量)

切记,核心是管理共享的可变状态,锁(内置锁、Lock锁)、同步容器类(Vector、Hashtable等)、并发容器类(ConcurrentHashMap、CopyOnWriteArrayList)、同步工具类(闭锁、信号量、栅栏)、线程池等都只是是管理共享的可变状态的工具。性能

相关文章
相关标签/搜索