简要JUC常识概念总结

JUC常识概念

  • 基础概念
    • 1.同步与异步
    • 2.并发与并行
    • 3.临界区
    • 4.阻塞与非阻塞
    • 5.死锁、饥饿、活锁
      • 死锁
      • 饥饿
      • 活锁
      • 原子性
      • 可见性
      • 有序性
        • 不能指令重排的规则:**Happen-Before规则**
  • 并发级别
      • 阻塞
      • 无饥饿
      • 无障碍
      • 无锁
      • 无等待

基础概念

Created: Aug 6, 2020 8:45 PM
Tags: 临界区, 原子性、可见性、有序性, 同步异步, 并发并行, 死锁、饥饿、活锁

1.同步与异步

用来形容一次方法调用。

  • 同步的方法调用一旦开始,调用者必须等到方法调用返回后才能继续。
  • 异步调用类似消息传递,执行后另一个线程进行操作,同时本线程立即返回

简要JUC常识概念总结_第1张图片

2.并发与并行

  • 并行偏重多个任务交替执行,多个任务直接可能还是串行的
  • 并发偏重同时执行

3.临界区

用来表示一种公共资源。可以被多个线程使用。但是每次只能有一个线程使用。线程需要等待其他线程使用完该资源。

4.阻塞与非阻塞

用来形容多线程之间的相互影响。

  • 阻塞在占用临界区资源时,其他线程必须挂起等待,该线程若不释放资源,其他所有阻塞在这个临界区的线程都不能工作
  • 非阻塞强调没有一个线程可以妨碍其他线程执行。所有线程都尝试不断前进。

5.死锁、饥饿、活锁

死锁

多个线程互相占用对方需要的资源,同时本身不愿意放弃自己的资源,导致死锁

![线程死锁]](https://img-blog.csdnimg.cn/img_convert/d98885594a3ef0970b7af25a57878e1b.png#pic_center)

饥饿

线程资源的分配不是根据先到先得的,获得资源存在了一定的“运气”,一个线程因为种种原因无法获得所需要的资源,导致无法执行,称为饥饿

活锁

多个线程互相谦让,资源始终在两个线程之间跳动,却没有被使用。

原子性

指一个操作不可中断。

对于32位的系统,long型的数据读写不是原子性的(long有64位)。
在32位的环境下,并发读写long数据,结果将很神奇。

可见性

当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道这个修改。串行程序不需要考虑可见性。

并行程序中,将可能发生问题

某个线程修改了某一个全局变量,其他线程不一定能立刻知晓改动。
简要JUC常识概念总结_第2张图片

因为线程之间操作不可见导致的指令重排问题

下侧的代码在运行时,看起来没什么问题,

public void T1(){
     
		r2 = A;
		B = 1;
}
public void T2(){
     
    r1 = B;
		A = 2;
}

重排后
A=2

r2=A=2;
B=1;

r1=B=1;

有序性

指令重排不保证多线程之间的有序,只能保证本线程内语义一致

类似上面的代码,指令重排将可能导致多线程之间操作逻辑错误。

不能指令重排的规则:Happen-Before规则

  • 程序顺序原则
  • volatile规则
  • 锁规则
  • 传递性
  • 线程的start()方法优于每一个动作
  • 线程所有操作先于线程的终结
  • 线程中断先于被中断的代码
  • 对象的构造函数执行、结束先于finalize()方法

Happen-Before规则主要保证指令重排不会破坏原有的语义结构

并发级别

Created: Aug 6, 2020 9:40 PM
Tags: 无等待, 无锁, 阻塞, 饥饿

由于临界区的存在,多线程之间并发必须受到控制。

根据控制并发的策略,将并发的级别进行分类,大致分为阻塞、无饥饿、无锁、无等待几种

阻塞

在其他线程释放资源前,当前线程无法继续执行。

使用synchronized关键字或重入锁。

无饥饿

非公平的锁允许“插队”的情况。公平的锁满足先来后到,饥饿将不会产生,所有线程都有机会执行。

无障碍

最弱的非阻塞调度。

两个线程进入临界区不会挂起。若监测到数据错误,将对修改进行回滚,确保数据安全。若无竞争发生,这完成工作,走出临界区。

隐含的问题:临界区存在严重的冲突,所有的线程都在回滚操作,没有一个能走出临界区。需要在此时保证有一个能够在有限时间内完成自己的操作。

实现方式之一:“一致性标记”,操作前保存标记,完成后进行检查。一样则正常。

存在的漏洞:该线程在临界区内运行时,第三者获取到了临界区,进行了操作,并将标记恢复,导致不能识别。

无锁

无锁的并行都是无障碍的。所有线程都能尝试对临界区访问。但,无锁的并发保证必然有一个线程能够在有限步内完成操作并离开临界区。

典型特点:无限循环,不断尝试修改。

无等待

在无锁的基础上进一步扩展。要求所有的线程都必须在有限步内完成,这样不会引起饥饿问题。

典型无等待:RCU(Read-Copy-Update)对数据的读不加控制。写数据时,获取数据副本,进行操作,合适的时机写回。

你可能感兴趣的:(春招冲关-Java后端,Java从入门到秃头,java,并发编程,多线程)