Java高并发程序设计(一)—————概念解读

引言

JAVA的高并发设计一直都是当今互联网开发的重要环节,从今天开始我们逐步学习《Java高并发程序设计》,并将本书的重要内容总结陈述,希望与大家共同进步。

几个基本认知

  • 同步(Synchronous)和异步(Asynchronous)
    同步和异步通常表示一次方法的执行,同步表示方法二只能在方法一执行完毕后执行,异步表示方法一执行过程中,方法二可能已经执行了。

  • 并发(Concurrency)和并行(Parallelism)
    并行是指严格的同时执行。并发是多个任务内部交替执行,一会运行A,一会运行B,对于外部观察者来说,好像是同时执行的。

  • 临界区
    临界区表示一种公共资源或者共享数据,可以被多个线程使用。

  • 阻塞(Bloking)和非阻塞(Non-Blocking)
    阻塞和非阻塞用来形容多线程之间的相互影响。比如一个线程占用了临界区资源,另外一个线程就要等这个线程结束。等待会导致线程挂起,这种情况叫做阻塞。
    非阻塞强调没有一个线程可以妨碍其他线程执行。

  • 死锁(DeadLock),饥饿(Starvation),和活锁(LiveLock)
    死锁是指多线程之间一直占用资源,不愿释放,导致一直等待,直到程序崩溃。
    饥饿是指某个线程或者线程组因为种种原因无法获得所需要的资源,导致一直无法执行。
    活锁是指线程主动释放资源给其他线程,但是其他线程也是主动释放,导致无法获取执行完毕的资源。

并发几个级别

  • 阻塞(Blocking)
    一个线程是阻塞的,那么在其他线程释放资源之前,当前线程无法执行。
    (synchronized和重入锁)
  • 无饥饿(Starvation-Free)
    线程之间具有优先级,如果使用非公平锁,可能导致低优先级的线程饥饿,所以使用公平锁可以防止饥饿。
  • 无障碍(Obstruction-Free)
    两个线程如果是无障碍的执行,就能够共享资源,共同修改资源,但是如果检测到有数据竞争,就会对自己的操作进行回滚。
    无障碍的线程不一定是安全的,倘若产生极端情况,临界区资源被严重竞争,大家都会滚自己的操作,没有一个线程能够走出临界区。
    一种无障碍的实现是依赖一个一致性标记来做的,线程在操作之前,都要提前读取并保存这个标记,操作之后再次读取,检查这个标记是否被更改过。如果不一致,重试操作。
    并且,任何对临界资源修改的线程,在修改之前,都要进行标志的更新。
  • 无锁(Lock-Free)
    无锁也是无障碍的,与之不同的是,无锁的并发必须保证有一个线程能够在有限步完成操作离开临界区。
  • 无等待(Wait-Free)
    无等待是无锁的一个拓展,他要求所有线程必须在有限步内完成,离开临界区。
    一种典型的无等待结构是RCU(Read-Copy-Update),基本思想是,对数据的读不做限制,写数据的时候,先取得原始数据副本,接着只修改副本数据,修改完成后,合适的时机回写数据。

并发的两个定律

将串行改为并发究竟能提高多少性能呢?主要有两个定律对这个问题进行解答

  • Amdahl
    加速比定义: 加速比=优化前耗时/优化后耗时
    n表示处理器个数,T表示时间,
    T1表示优化前耗时(只有一个处理器的耗时),Tn表示使用n个处理器优化后的耗时。F是程序中只能串行执行的比例,那么(1-F)是并行执行的比例。
    加速比= T1/Tn ;
    Tn=T1(F+(1/n)/(1-f)) 带入上式得出:
    T1/Tn = 1/(F+(1-F)/n)
    我们可以发现,就算是n无穷大,加速比的大小完全在F的影响下。
    增加减少串行数量,适当增加处理器。

  • Gustafson
    这部分请自行查阅书籍,这里不再赘述。

关于JMM

JMM指的是JAVA的内存模型。JMM关键技术点都是围绕着多线程的原子性,可见性和有序性建立的,我们首先讲一下这三个概念。

  • 原子性(Atomicity)
    原子性是指一个操作是不可以中断的。
    举个栗子:一个变量i,某个线程对他操作记为1,另外一个线程对他操作记为-1,那么他要么是1,要么是-1,总是确定的,线程1和线程2之间是没有干扰的,这就是原子性的特点。
    注:如果是long型的数据,在32位系统中会出问题,原因是long型是64位,线程执行时会丢失数据,导致数据串位。

  • 可见性
    可见性是指当一个线程修改了某个共享变量的值,其他线程能否立即知道这个修改。

  • 有序性
    有序性的原因是线程执行时,可能会产生指令重排 ,为什么会产生指令重排呢?
    我们先来了解下一个指令的执行过程
    取值IF——>译码和取寄存器操作数ID——>执行或者有效地址计算EX——>存储器访问MEM——>写回WB
    由于上边的每个步骤可能使用不同的硬件完成,因此攻城狮发明了流水线技术,流水线技术使得第一个指令用完某个硬件后立即交付,第二条指令如果用到交付额硬件立即可以使用。但这里有个问题是某个指令可能因为某些原因阻塞,这时难道让所有的指令进行等待么?显然是不合理的,应该把后边没有用到这个硬件的指令提前。这样就发生了指令重排。
    那么,那些指令不能重排呢?

  • 不能重排的基本原则
    (1)程序顺序原则:一个线程内保证语义的串行性
    (2)volatile原则:volatile变量的写,先发生于读,这个保证了volatile的可见性。
    (3)锁规则:解锁必然发生在加锁之前
    (4)传递性:A先于B,B先于C,那么A先于C。
    (5)线程的start()方法最先执行
    (6)线程的所有操作先于线程的终结(Thread.join())
    (7)对象的构造方法执行和结束先于finalize()方法

第一章总结结束,下一章我们来看一下JAVA并行程序基础

作者:select you from me
链接:https://mp.csdn.net/mdeditor/95772392
来源:CSDN
转载请联系作者获得授权并注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值