有资源网

搜索
有资源网 首页 编程语言 查看内容

java高并发系列 - 第2天:并发级别

2019-7-26 01:05| 发布者: admin| 查看: 201| 评论: 0

摘要: 由于临界区的存在,多线程之间的并发必须受到控制。根据控制并发的策略,我们可以把并发的级别分为壅闭、无饥饿、无停滞、无锁、无等候几种。 壅闭 一个线程是壅闭的,那么在其他线程开释资源之前,当前线程无法继承

由于临界区的存在,多线程之间的并发必须受到控制。根据控制并发的策略,我们可以把并发的级别分为壅闭无饥饿无停滞无锁无等候几种。

壅闭

一个线程是壅闭的,那么在其他线程开释资源之前,当前线程无法继承实行。当我们利用synchronized关键字或者重入锁时,我们得到的就是壅闭的线程。

synchronize关键字和重入锁都试图在实行后续代码前,得到临界区的锁,假如得不到,线程就会被挂起等候,直到占有了所需资源为止。

无饥饿(Starvation-Free)

假如线程之间是有优先级的,那么线程调度的时候总是会倾向于先满足高优先级的线程。也就是说,对于同一个资源的分配,是不公平的!图1.7中表现了非公平锁与公平锁两种环境(五角星表现高优先级线程)。对于非公平锁来说,系统允许高优先级的线程插队。这样有大概导致低优先级线程产生饥饿。但假如锁是公平的,按照先来后到的规则,那么饥饿就不会产生,不管新来的线程优先级多高,要想得到资源,就必须乖乖列队,这样全部的线程都有时机实行。

编程语言-java高并发系列 - 第2天:并发级别(1)

无停滞(Obstruction-Free)

无停滞是一种最弱的非壅闭调度。两个线程假如无停滞地实行,那么不会因为临界区的问题导致一方被挂起。换言之,各人都可以大摇大摆地进入临界区了。那么各人一起修改共享数据,把数据改坏了怎么办呢?对于无停滞的线程来说,一旦检测到这种环境,它就会立即对自己所做的修改举行回滚,确保数据安全。但假如没有数据竞争发生,那么线程就可以顺遂完成自己的工作,走出临界区。

假如说壅闭的控制方式是灰心策略,也就是说,系统认为两个线程之间很有大概发生不幸的辩论,因此以掩护共享数据为第一优先级,相对来说,非壅闭的调度就是一种乐观的策略。它认为多个线程之间很有大概不会发生辩论,或者说这种概率不大。因此各人都应该无停滞地实行,但是一旦检测到辩论,就应该举行回滚。

从这个策略中也可以看到,无停滞的多线程步伐并不肯定能顺畅运行。因为当临界区中存在严峻的辩论时,全部的线程大概都会不断地回滚自己的操纵,而没有一个线程可以走出临界区。这种环境会影响系统的正常实行。以是,我们大概会非常盼望在这一堆线程中,至少可以有一个线程能够在有限的时间内完成自己的操纵,而退出临界区。至少这样可以保证系统不会在临界区中举行无穷的等候。

一种可行的无停滞实现可以依靠一个"一致性标志"来实现。线程在操纵之前,先读取并生存这个标志,在操纵完成后,再次读取,查抄这个标志是否被更改过,假如两者是一致的,则阐明资源访问没有辩论。假如不一致,则阐明资源大概在操纵过程中与其他线程辩论,需要重试操纵。而任何对资源有修改操纵的线程,在修改数据前,都需要更新这个一致性标志,表现数据不再安全。

数据库中乐观锁,应该比较熟悉,表中需要一个字段version(版本号),每次更新数据version+1,更新的时候将版本号作为条件举行更新,根据更新影响的行数判断更新是否成功,伪代码如下:

1.查询数据,此时版本号为w_v
2.打开事务
3.做一些业务操纵
4.update t set version = version+1 where id = 记载id and version = w_v;//此行会返回影响的行数c
5.if(c>0){
        //提交事务
    }else{
        //回滚事务
    }

多个线程更新同一条数据的时候,数据库会对当前数据加锁,同一时刻只有一个线程可以实行更新语句。

无锁(Lock-Free)

无锁的并行都是无停滞的。在无锁的环境下,全部的线程都能尝试对临界区举行访问,但差异的是,无锁的并发保证肯定有一个线程能够在有限步内完成操纵脱离临界区。

在无锁的调用中,一个典型的特点是大概会包罗一个无穷循环。在这个循环中,线程会不断尝试修改共享变量。假如没有辩论,修改成功,那么步伐退出,否则继承尝试修改。但无论如何,无锁的并行总能保证有一个线程是可以胜出的,不至于三军覆没。至于临界区中竞争失败的线程,他们必须不断重试,直到自己获胜。假如运气很不好,总是尝试不成功,则会出现雷同饥饿的先写,线程会停止。

下面就是一段无锁的示意代码,假如修改不成功,那么循环永久不会停止。

while(!atomicVar.compareAndSet(localVar, localVar+1)){
        localVal = atomicVar.get();
}

无等候

无锁只要求有一个线程可以在有限步内完成操纵,而无等候则在无锁的底子上更进一步扩展。它要求全部线程都必须在有限步内完成,这样不会引起饥饿问题。假如限定这个步调的上限,还可以进一步分解为有界无等候和线程数无关的无等候等几种,他们之间的区别只是对循环次数的限定差异。

一种典型的无等候结果就是RCU(Read Copy Update)。它的根本头脑是,对数据的读可以不加控制。因此,全部的读线程都是无等候的,它们既不会被锁定等候也不会引起任何辩论。但在写数据的时候,先获取原始数据的副本,接着只修改副本数据(这就是为什么读可以不加控制),修改完成后,在符合的时机回写数据。

java高并发系列

  • java高并发系列 - 第1天:必须知道的几个概念
  • java高并发系列 - 第2天:并发级别
  • java高并发系列 - 第3天:有关并行的两个重要定律
  • java高并发系列 - 第4天:JMM相干的一些概念
  • java高并发系列 - 第5天:深入明白历程和线程
  • java高并发系列 - 第6天:线程的根本操纵
  • java高并发系列 - 第7天:volatile与Java内存模型
  • java高并发系列 - 第8天:线程组
  • java高并发系列 - 第9天:用户线程和保卫线程
  • java高并发系列 - 第10天:线程安全和synchronized关键字
  • java高并发系列 - 第11天:线程中断的几种方式
  • java高并发系列 - 第12天JUC:ReentrantLock重入锁

java高并发系列连载中,总计估计会有四五十篇文章,可以关注公众号:javacode2018,获取最新文章。
编程语言-java高并发系列 - 第2天:并发级别(2)

java高并发系列互换群
编程语言-java高并发系列 - 第2天:并发级别(3)


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

鲜花

握手

雷人

路过

鸡蛋

最新评论

返回顶部