美文网首页
java多线程(核心篇)第二章

java多线程(核心篇)第二章

作者: jiahzhon | 来源:发表于2019-12-29 18:13 被阅读0次

第二章

2.1 串行、并发与并行
image.png
  1. 并行可以被看作并发的一个特例。因此,并发往往是带有部分串行的并发,而并发的极致就是并行。
  2. 从软件的角度来讲,并发就是再一段时间内以交替的方式去完成多个任务,而并行就是以齐头并进的方式去完成多个任务。并发也未必就比串行的处理效率更高或者效率提高那么明显。
  3. 从硬件的角度来说。处理器可以使用时间片分配的技术来实现在同一段时间内运行多个线程,因此一个处理器就可以实现并发。
2.2 竞态
  1. 一个计算结果的正确性与时间有关的现象就被称为竞态。
  2. 竞态往往伴随着读取脏数据问题,即线程读取到一个过时的数据、丢失更新问题,即一个线程对数据所做的更新没有体现在后续其他线程对该数据的读取上。
  3. 竟态的模式与产生的条件
    • read-modify-write读取一个共享变量的值(read),然后根据就该值做一些计算(modify)接着更新该共享变量的值(write)。
    • check-then-act读取某个共享变量的值,根据该变量的值决定下一步的动作是什么。
  4. 对于局部变量(包括形式参数和方法体内定义的变量),由于不同的线程各自访问的是各自的那一份局部变量,因此局部变量的使用不会导致竟态
  5. synchronized关键字会使其修饰的方法在任一时刻只能够被一个线程执行,这使得该方法涉及的共享变量在任一时刻只能够有一个线程访问(读、写),从而避免了这个方法的交错执行而导致的干扰,从而消除了竟态。
2.3 线程安全问题

线程安全问题概况表现为三个方面:原子性、可见性和有序性

2.3.1.原子性

  1. 对于涉及共享变量访问的操作,若该操作从其执行线程以外的任意线程来看是不可分割的,那么该操作就是原子操作。即其他线程不会“看到”该操作执行了部分的中间效果。
  2. 原子操作是针对访问共享变量的操作而言的。也就是说,仅涉及局部变量访问的操作无所谓是否是原子的,或者干脆把这一类操作都堪称原子操作。
  3. 单线程环境下一个操作无所谓是否具有原子性。
  4. 在Java语言中,long型和double型以外的任何类型的变量的写操作都是原子操作,即对基础类型(long/double除外,仅包括byte、boolean、short、char、float和int)的变化和引用型变量操作都是原子性的。
  5. volatile关键字修饰的long/double型变量的写操作具有原子性。
  6. volatile关键字仅能够保障变量写操作的原子性,它并不能保障其他操作(例如read-modify-write操作和check-then-act操作)

2.3.2.可见性

  1. 可见性就是指一个线程对共享变量的更新的结果对于读取相应共享变量的线程而言是否可见的问题。
  2. 可见性与计算机的存储系统有关。每个处理器都有寄存器。如果两个线程分别运行在不同的处理器上,而这两个线程所共享的变量却被分配到寄存器上进行存储,那么就会有可见性问题。即使某个共享变量被分配到主内存中存储,要和不能保证变量的可见性。因为处理器对主内存的访问并不是直接访问,而是通过其高速缓存子系统进行的。可能只更新到写缓存器中,都不会到达高速缓存,更别说主内存。
  3. 为了保障保障可见性,我们必须使一个处理器对共享变量所做的更新最终被写入该处理器的高速缓存或者主内存中,这个过程被称为冲刷处理器缓存。
  4. volatile作用:1.提示JIT编译器被修饰的变量可能被多个线程共享,以阻止JIT编译器做出可能导致程序运行不正常的优化。(例如下面例子toCancel没有足够提示让编译器知道还有其他线程访问他,为了避免重复读取变量,提高效率,自动优化,导致退不出。解决方法就是给toCancel加volatile关键字。)另外一个作用就是读取一个volatile关键字修饰的变量会使相应的处理器执行刷新处理器缓存的动作。
image.png
  1. 父线程在启动子线程之前对共享变量的更新对于子线程来说是可见的。(可能是1,可能是2)


    image.png
  2. 一个线程终止后该线程对共享变量的更新对于调用该线程的join方法的线程而言是可见的。(一定是1)


    image.png

2.3.3.有序性

  1. 有序性指在什么情况下一个处理器上运行的一个线程所执行的内存访问操作在另一个处理器上运行的其他线程看来是乱序的。
  2. 在源代码顺序与程序顺序不一致,或者程序顺序与执行顺序不一致的情况下,我们就说发生了指令重排序。
  3. volatile关键字,synchronized关键字都可以禁止重排序。
2.4 上下文切换
  1. 单处理器上也能够以多线程的方式实现并发,即一个处理器可以在同一时间段内运行多个线程。通过时间片。时间片决定了一个线程可以连续占用处理器运行的时间长度。
  2. 一个线程被暂停,即被剥夺处理器的使用权,另外一个线程被选中开始或者继续运行的过程就叫作线程上下文切换。切出和切出那一刻相应的线程所执行的任务进行到了什么程度。这个进度信息就被称为上下文。
2.5 资源争用与调度
  1. 同一时间内,处于运行状态(Running)的线程数量越多,并发的程度越高,简称高并发。
  2. 决定哪个线程会被授予该资源的独占权,即选择哪个申请者占用该资源的过程就是资源的调度。
  3. 公平调度策略中的资源申请者总是按照先来后到的顺序来获得资源的独占权。
  4. 一般来说,非公平调度策略的吞吐率较高,即单位时间内它可以为更多的申请者调配资源。缺点是申请者获得相应资源的独占权所需时间的偏差可能比较大。
  5. 在资源的持有线程占用资源的时间相对长或线程申请资源的平均间隔时间相对长的情况下,或者对资源申请所需的时间偏差有要求(即时间偏差较小)的情况下,可以考虑使用公平调度策略。

相关文章

网友评论

      本文标题:java多线程(核心篇)第二章

      本文链接:https://www.haomeiwen.com/subject/fpxuoctx.html