高效并发

原创 2018年04月17日 15:55:50

高效并发

1. 概述

1.1. 引入缓存

由于内存和处理之间的速度差异,所以说在内存和处理之间加入一层高速缓存。将需要运算的数据复制到缓存中,使运算快速执行,处理器执行后,再将缓存中的结果同步到内存。

1.2. 数据不一致性

引入缓存解决了内存和处理器速度不匹配问题,但是引入了缓存不一致性问题。在多处理器系统中,每一个处理器都有自己的缓存,而它们共享主内存。当多个处理器处理主内存中同一块区域的数据时,将可能导致数据不一致问题。

1.3. 处理器的乱序执行

为了使得处理器的运算单元能够充分利用,处理器会把输入的代码打乱顺序执行。处理器计算之后将计算结果进行重组,使得重组后的结果与代码顺序执行的结果相同,但是并不保证各个语句的计算结果的先后顺序与代码中的顺序相同,因此如果一个任务以来另一个任务的中间结果,那么其顺序性不能靠代码的顺序来保证。与处理器的乱序优化相似,java虚拟机使用了重排序优化。

2. JVM的内存模型

Java内存模型的目标是:定义程序中变量的访问规则。这里的变量不是指方法中的局部变量和参数(以内这些变量存储在Java虚拟机栈中,是线程私有的,不是共享变量,不存在线程竞争),指的是实例的字段,静态变量,构成数组对象的元素。

2.1. 主内存和工作内存

Java内存模型可以分为主内存和工作内存。所有的变量都存储在主内中,每一个线程都有自己的一个工作内存。

线程的工作内存中使用的变量是主内存中变量的一个副本。对变量的所有操作都只能在工作内存进行,不能直接对主内存中的变量进行访问。不同线程之间,不能够直接的访问对方工作空间中的变量,只能够通过主内存间接的传递变量。

 

2.2. 内存间的交互操作

Java内存模型中定义了8种操作:

lock(锁定):用于主内存中的变量,把一个变量标识为线程独占状态。

unlock(释放):用于主内存中的变量,把一个处于锁定状态的变量释放,释放后的变量才可以被其它线程锁定。

Read(读取):用于主内存中的变量,把主内存中变量的值读到工作内存中。

Load(载入):用于工作内存中的变量,将read操作从主内存中读取的变量的值放入到工作内存的变量的副本中。

Use(使用):用于工作内存中的变量,将工作内存中变量的值传给执行引擎,每当虚拟机遇到一个需要变量值的字节码指令时都会执行该操作。

Assign(赋值):用于工作内存的变量,将执行引擎返回值赋值给工作内存中的变量,当虚拟机遇到给变量赋值的指令时就会执行该操作。

Store(存储):用于工作内存的变量,将工作内存中变量的值传到主内存中

Write(写入):用于主内存中的变量,将store从工作内存中出入到主内存中的值放入到变量中。

2.3. Volatile关键字

保证变量对所有线程是可见的,即当一个线程修改了变量的值,其他线程可以立即知道新值。

对于volatile修饰的变量,线程每次使用前都要从主内存刷新,因此可以保证线程的可见性。

 

3. 线程安全

3.1. synchronized

synchronized关键字,synchronized关键字在编译时,会在同步代码块的前后分别添加monitorentermonitorexit指令。在执行monitorenter指令时,首先要去获取对象的锁,如果获取成功,或者当前线程已经拥有该对象锁,则将锁计数器加1。在执行monitorexit指令时,将锁计数器减1,如果锁计数器为0,则释放锁,其他在该对象锁上竞争等待的线程重新开始竞争锁。

synchronized是可重入的,如果一个线程持有锁对象,再重新请求该所对象时不会阻塞。在锁对象被线程持有时,其他线程获取锁对象会阻塞等待,直到持有该锁对象的线程释放锁,才会重新竞争。

Java.until.Concurrent包下的ReentrantLock也可以实现同步,ReentrantLock使用lockunlock来加锁和释放锁。ReentrantLock有以下特性:

(1) 可设置中断:如果等待持有锁的线程释放锁的事件太长,可以中断等待区执行其他任务。

(2) 可设置公平锁

(3) 可以绑定若干个条件。Condition类。

3.2. 阻塞同步

阻塞同步会带来系统的性能问题,线程的阻塞和唤醒都会带来性能问题。这是一种悲观策略。对于同步问题不一定都要进行加锁,还有一种乐观的策略,非阻塞同步。

3.3. CAS算法

CAS算法有三个操作数,变量的内存地址V,期望的旧变量值A,新的值B。如果V中的值与期望的旧值A相同,则用新值A来替换V的值。否则就不执行更新。CAS算法有一个ABA问题。

4. 锁优化

4.1. 自旋锁

阻塞同步,对于线程的挂起和唤醒会给操作系统的并发性能增加很多压了。实际上共享数据的锁定状态只持续很短的一段时间,为了这点时间去执行挂起和唤醒线程操作不值得。而自旋锁,如果具有一个以上的处理器,允许两个或以上线程同时执行,如果一个锁对象已经被一个线程持有,则另一个线程要稍等一会,但是不会放弃CPU的执行权,看看线程是否很快就会释放锁,只要让线程进入忙循环状态(自旋)。

4.2. 自适应自旋

对于自旋锁,如果线程长时间不释放锁,则处于自旋状态的线程就会浪费处理器的资源。所以引入了自适应自旋,自适应意味着自旋时间不固定,而是根据上一次在同一个锁上的自旋时间和锁的拥有者状态决定的。如果在同一个锁上,自旋刚刚获得锁,并且持有锁的线程正在执行,则将自旋等待的时间设置长一点。如果在该对象锁上,很少通过自旋来获得锁,则省略使用自旋获取锁,直接阻塞等待。

4.3. 轻量级锁

根据经验对于绝大部分的锁在整个同步期间是不存在竞争的。所以引入了轻量级锁。在执行monitorenter时,需要去获取锁对象。判断对象头的Mark Word中的标志位,如果标志位为01(没有锁定),则在线程栈帧中存储一个名为锁记录的空间,将Mark Word复制到锁记录空间。然后使用CAS操作尝试将Mark Word替换为指向当前线程的指针。如果替换成功则表示获取锁成功,并将Mark Word标志位置为00(轻量级锁)。如果操作失败则检查Mark Word中指针是否指向当前线程,如果指向则表示当前线程已经拥有锁,可以直接进入同步代码块执行。否则,说明这个对象的锁已经被其他线程拥有。

如果存在两个以上的线程竞争锁,则轻量级锁不再有效,膨胀为重量级锁,将锁标志位置为10Mark Word中存储的是重量级锁的指针,后面等待锁的线程进入阻塞状态。

释放锁也是使用CAS操作,如果Mark Word指向当前线程,则使用CAS操作将当前锁记录中的数据替换回Mark Word中,如果替换成功,则锁释放,如果没有替换成功则表示有线程尝试竞争锁,则在释放锁的同时唤醒等待的线程。

4.4. 偏向锁

根据经验,锁对象大多数情况下往往只被某一个线程获取,所以引入了偏向锁。在开启偏向锁模式下,锁对象第一次被线程获取的时候,会将Mark Word中的锁标志位置为01(偏向锁),并使用CAS操作将获取该偏向锁的线程ID记录在MarkWord中,如果操作成功,则该线程再进入该锁对象相关的同步代码块中,就不需要进行同步操作。

如果有其他线程尝试获取锁对象,则偏向模式结束。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_31638095/article/details/79976036

Java高效并发

Java高效并发1.并发和并行的区别简而言之,并发就是一段时间间隔内发生的多个任务,不一定同时执行,可能是交替执行的。并行是在同一时间点执行的任务。网站最大连接数指的是并发,如1000个socket,...
  • lincolnmi
  • lincolnmi
  • 2016-01-10 19:46:11
  • 1333

两种高效的事件处理模式和并发模式

半同步/半异步模式: 先解释一下同步和异步的区别,在并发模式中,这里的“同步"指的是程序完全按照代码的顺序执行,“异步”指的是程序的执行需要由系统事件来驱动,比如说信号、中断等。下图就清楚的解释了同步...
  • u011438608
  • u011438608
  • 2015-03-31 18:08:57
  • 3303

高并发高效数据库连接池

来源:http://www.lcfms.cn:81/ /*  * 高并发高效数据库连接池  * 作者:老成 http://www.lcfms.cn:81/  */ package c...
  • su492253299su
  • su492253299su
  • 2015-11-30 09:55:00
  • 2719

java并发——构建高效且可伸缩的结果缓存

几乎所有的服务器应用都会使用某种形式的缓存。重用之前的计算结果能降低延迟,提高吞吐量,但却要消耗更多内存。看上去简单的缓存,可能会将性能瓶颈转变成伸缩性瓶颈,即使缓存是用来提高单线程性能的。本文将开发...
  • ly908979139
  • ly908979139
  • 2017-04-09 22:58:25
  • 665

并发编程学习:使用读写锁来编写高效率的缓存系统

package com.lei.lock;/* *@author leixingbang_sx *Mail:leixingbang_sx@qiyi.com *@create 2016/1/20 10:...
  • leixingbang1989
  • leixingbang1989
  • 2016-01-21 11:52:57
  • 769

JVM之高效并发

一.java内存模型与线程 1.Java内存模型 (1)主内存与工作内存 主内存存放变量(包括实例字段, 静态字段, 构成数组对象的元素), 直接对应物理硬件的内存 工作内存 是线程自己的工作...
  • m0_37838381
  • m0_37838381
  • 2018-03-19 09:23:57
  • 15

java并发之同步工具类一之闭锁Latch

java同步工具类(指jdk1.5版本)主要有闭锁(Latch)、信号灯(semaphore)和栅栏(barrier)。本篇作为开篇,先讲闭锁。闭锁就相当于一扇门,在制定的线程到达后这扇门才打开,后续...
  • jerryJavaCoding
  • jerryJavaCoding
  • 2017-12-24 14:12:56
  • 81

服务器两种高效的并发模式

服务器两种高性能并发模式
  • qq_29422251
  • qq_29422251
  • 2017-07-16 10:00:11
  • 264

tcp高效率并发服务器

  • 2015年06月18日 21:07
  • 2KB
  • 下载

《深入理解java虚拟机-高效并发》读书笔记

Java内存模型与线程 概述   多任务处理在现代计算机操作系统中几乎已是一项必备的功能,多任务运行是压榨手段,就如windows一样,我们使劲的压榨它运行多个任务,俱要high又要耍。并发则是另...
  • zk65645
  • zk65645
  • 2017-03-01 15:31:43
  • 336
收藏助手
不良信息举报
您举报文章:高效并发
举报原因:
原因补充:

(最多只允许输入30个字)