Java高并发系列(一)——概念篇

一、并发基础概念

  1. 同步(Synchronous)&异步(Asynchronous)
  • 同步方法:一旦开始调用同步方法,调用者必须等到方法调用得到结果后才能返回,之后才能进行下一个动作。
  • 异步方法:异步方法开始之后,方法调用会立刻返回,不用等到方法结果返回即可继续进行下一个动作。等到异步调用真正完成且需要用到结果时,则会通知调用者。
  1. 并发(Concurrency)&并行(Parallelism)
  • 并发:并发指的是同一时段内有多个任务交替进行,即某一瞬间一般只有一个任务正在执行。
  • 并行:并行指的是同一时刻下,可以有多个任务同时进行着。
  • 操作系统系统中任务执行是并发的还是并行的?
    如果是CPU只有单个处理单元,即只有一个核心且不考虑超线程的CPU结构,那么这种时候就只能并发处理了,毕竟CPU中的PC一次只能读取一条指令,也就只能交替处理了。
    而多核心CPU或超线程CPU由于有多套处理单元,因此能在同一时间内同时执行多个任务。虽然每个处理单元上处理的任务是并发执行的,但是整体来看,整个系统的任务执行的并行方式的。
    那么你可能会问,为什么不是高并行执行呢?这是因为我们编写的是一个个的程序,程序执行之后就变为进程,进程通过启动多个线程进行任务处理从而实现并发执行。更简单地说,并发性是程序的属性,我们面向的是程序,而不是整个系统(单个机器或者集群),并行只是系统属性的一种外在表现。
  • 多核CPU由于性能强劲,已经被广泛使用,高并发编程的目的就是为了更高效且正确利用CPU,以更好地发挥CPU地性能。
  1. 进程(Process)&线程(Thread)
  • 进程:进程是操作系统资源分配的基本单位。进程可分为单线程进程和多线程进程,也就是说进程至少含有一个线程且该线程为主线程(main函数所在线程)。
  • 线程:线程又叫轻量级进程,是任务调度和执行的基本单位。线程必须由进程启动,线程含于进程。
  • 为什么要有线程?
    假设一下,如果没有线程,进程想同时执行其他任务时,只能通过开启新进程进行处理。当一次性想执行的任务量一大,那么就会频繁的创建进程,而创建进程需要系统分配资源、分配PID等工作,如果我们开启这个进程只是想简单地求个和,那么创建进程时造成的空间和时间开销就是大题小做,而且还需进行上下文保存和切换。我们完全可以使用父进程的空间和资源,从而避免重新分配空间、分配PID等工作,此时线程就体现了它的作用了——减少进程切换带来的开销工作。
  1. 临界区

临界区表示的是一种允许多个线程使用但同一时间只能有一个线程使用它的公共资源或共享数据,一旦临界区资源被占用其他线程要使用这个资源就必须等待。

  1. 阻塞(Blocking)&非阻塞(Non-Blocking)

阻塞:如果一个线程占用了临界区,那么其他线程想要使用这个临界区时就必须等待,等待会导致线程挂起,这种情况就是阻塞,直到临界区解除占用,其他线程中的某个线程进入临界区之后这个线程才解除阻塞。

非阻塞:非阻塞强调的是每个线程都能各自不断前向执行,而不会被其他线程影响。

  1. 死锁&活锁&饥饿

死锁:死锁指的是系统中所有的线程由于竞争资源且又不释放自身已占有资源造成的一种所有线程都进入阻塞状态的现象,在没有外力作用下是线程的阻塞不能解除从而导致永久阻塞。

  • 死锁产生的四个条件:
  • ①互斥:临界区资源一次只允许一个线程进行使用,其他线程只能等该线程结束使用后才能进入临界区。
  • ②请求并保持:线程在请求其他临界区资源的同时不会释放本身已经有的临界区资源的使用权。
  • ③不可抢占:临界区资源不能被抢占,线程A在使用临界区资源时,其他线程不能抢占这个资源,除非线程A自己释放。
  • ④循环等待:资源竞争形成环路,比如线程A想要线程B占用的资源,线程B想要线程C占用的资源,线程C想要线程A占用的资源,但由于线程不释放本身资源所以所有线程都进入等待状态。

活锁:线程申请资源时虽然没有阻塞,但不断地尝试申请资源却申请不到,导致一直运行且做的是无用功。比如小巷里两个人相遇,两人互相让行,但是总向同一边移动,导致两人左右摇摆都过不去。

饥饿:线程申请某个临界区资源后长时间等待该临界区资源的使用权限的情况。

二、并发级别

  1. 阻塞

线程在获得请求资源后才能继续往下运行,否则无法继续执行。如synchronized关键字与重入锁。

  1. 无饥饿(Starvation-Free)

所有线程获得资源的可能是公平的,不会产生饥饿。比如按优先级排序的线程队列,如果新的高优先级的线程进来会排在低优先级的前面,这对低优先级来说是不公平的,很有可能造成饥饿。而不管优先级的,严格按照先来后到的顺序进行排队,那么就是公平的。

  1. 无障碍(Obstruction-Free)

无障碍是一种最弱的非阻塞调度。多个线程如果无障碍地执行,那么所有线程都可以进入临界区并进行修改,一旦发现产生冲突就回滚自己的操作。如果没有数据竞争发生,那么线程就顺利完成自己的任务然后离开临界区。

  1. 无锁(Lock-Free)

无锁的并行都是无障碍的。无锁的情况下,所有的线程都能尝试访问临界区。如果线程竞争资源成功则完成任务并退出临界区,而如果线程竞争资源失败则持续尝试直到竞争成功。无锁能保障至少有一个线程能在有限步内抢到资源并完成任务,但对于长时间未抢到资源的线程会造成饥饿。

  1. 无等待(Wait-Free)

无等待是在无锁的基础上进一步的扩展。无等待要求所有线程都必须在有限步内都完成任务,这样就不会产生饥饿的问题了。
典型的无等待结构是RCU(Read Cpoy Update),它的基本思想是,对数据的读不加控制,所以读线程都是无等待的;对于写操作,需要从主存获取数据副本,修改时只修改这个副本,然后在适当的时间写回数据。

三、下篇

下一篇:Java高并发系列(二)——JMM模型与并发三大问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值