1 设计模式

(1) 单例模式

保证一个类只能一个对象实现。正常的单例模式分为懒汉式和饿汉式,饿汉式就是把单例声明称static a=new A(),系统第一次调用的时候生成(包括调用该类的其他静态资源也会生成),懒汉式就是系统调用get函数的时候,加个锁判断单例对象是否存在,存在就返回不存在就声明一个。好一点的懒汉式应该把单例加一个静态内部类,第一次访问的类的时候静态内部类不会初始化,当调用的get方法的时候再实例化,这样不用加锁效率高一些,

public class StaticSingleton {

   private StaticSingleton(){

     System.out.println("StaticSingleton is create");

  }

   private static class SingletonHolder {

     private static StaticSingleton instance = new StaticSingleton();

   }

   public static StaticSingleton getInstance() {

     return SingletonHolder.instance;

   }

(2)不变模式  类和变量都声明为final,只要创建就不可变,常见的string Integer Double等都是不可变。

(3) future模式  客户端请求服务端数据,如果服务端处理时间较长,可以返回一个空值(类似代理),启动一个线程专门设值。客户端可以先干别的,当想要试用这个值时,可以从代理里拿,如果代理值已经设置好直接返回,如果没设置好则wait,等设置好了的时候notify。  可以向excutor里提交一个实现了Collable的对象,会返回一个Future,然后使用这个future.get()拿值。

(4) 生产者消费者模式  专门有生产者生产数据,消费者消费数据,中间靠线程安全的队列作为公共区域,各线程都从这个区域里写值和读值。各个线程无需了解对存在,只要负责自己的事情即可,也符合开闭原则。

2 锁优化

具体思路:减少锁持有时间,减小锁粒度,锁分离,锁粗化,锁消除。

(1)减少锁持有时间  尽量少的加锁代码,例如用具体代码段代替方法加锁。

 (2)减小锁粒度   把大对象尽量改成小对象,增加并行度减少锁竞争。同时有利于偏向锁,轻量级锁。例如ConcurrentHashMap

  (3)锁分离   读写分离,读读可重入,读写互斥,写写互斥。另一种分离,例如 LinkedBlockingQueue ,存数据和取数据从队列两端操作,两端各自加锁控制即可,两端的锁互不影响。

(4)锁粗化 如果一段程序要多次请求锁,锁之间的代码执行时间比较少,就应该整合成一个锁,前提是不用同步的部分执行时间短。例如for循环里面申请锁,如果for循环时间不长,可以在for外面加锁。

(5)锁消除 编译器级别的操作,如果jdk发现锁不可能被共享,会擦除这个锁。原理是逃逸分析,例如stringbuffer,本身操作是加锁的,如果只在局部使用不存在并发访问,那么会擦除锁,如果对象逃逸出去例如赋值给全局变量等,面临并发访问,就不会擦除锁。可以通过jvm参数来指定是否使用锁消除。

3 jdk的锁优化  sychronized的优化,由虚拟机完成

(1)偏向锁  在竞争比较少的情况下,会使用偏向锁来提高性能。

*对象头 markword,共32位,存hash,锁信息(指向锁的指针),垃圾回收标志(偏向锁id),年龄信息,偏向锁线程id,monitor信息等。

  一个线程争取到对象资源时,对象会在对象头中标记为偏向,并且将线程id写入到对象头中,下次如果这个线程再来可以不通过锁竞争直接进入同步块。当其他线程访问的时候,偏向结束,升级为轻量级锁。所以在竞争激烈的场景下偏向锁会增加系统负担,jvm默认是开启偏向锁的,可以通过jvm参数设置取消偏向锁

*偏向锁只需要在置换ThreadID的时候依赖一次CAS原子指令,在只有一个线程执行同步块时进一步提高性能。

(2)轻量级锁 轻量级锁所适应的场景是线程交替执行同步块的情况,如果存在同一时间访问同一锁的情况,就会导致轻量级锁膨胀为重量级锁。

   轻量级锁的加锁过程 :

      1)在代码进入同步块的时候,如果同步对象锁状态为无锁状态(偏向锁也是无锁),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝。

      2)拷贝对象头中的Mark Word复制到锁记录中。

      3)拷贝成功后,虚拟机将使用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指针,并将Lock record里的owner指针指向object mark word。

      4)如果这个更新动作成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位设置为处于轻量级锁定状态。

     5)如果这个更新操作失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是就说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块继续执行。否则说明多个线程竞争锁,轻量级锁就要膨胀为重量级锁,锁标志的状态值变为“10”,Mark Word中存储的就是指向重量级锁(互斥量)的指针,后面等待锁的线程也要进入阻塞状态。 而当前线程便尝试使用自旋来获取锁,自旋就是为了不让线程阻塞,而采用循环去获取锁的过程。

轻量级锁解锁时,把复制的对象头替换回去(cas)如果替换成功,锁结束,如果失败,说明有竞争,升级为重量级锁(先会自旋一下等等看),notify 唤醒其他等待线程。

  * 轻量级锁是为了在线程交替执行同步块时提高性能。

(3)自旋锁

轻量级锁加锁失败以后,可能先自旋一段时间,尝试获得轻量级锁,不会着急升级为重量级锁挂起。如果自旋过多,会造成cpu资源浪费,JDK采用了适应性自旋,简单来说就是一开始设置固定自旋次数,线程如果自旋成功了,则下次自旋的次数会更多,如果自旋失败了,则自旋的次数就会减少。

*自旋如果成功,可以省略线程挂起的时间。jdk7以后默认使用。

3 jdk8新特性

(1)LongAdder  类似automicLong, 但是提供了“热点分离”。过程如下:如果并发不激烈,则与automicLong 一样,cas赋值。如果出现并发操作,则使用数组,数组的各元素之和为真实value,让操作分散在数组各个元素上,把并发操作压力分散,一遇到并发就扩容数组,最后达到高效率。一般cas如果遇到高并发,可能一直赋值失败导致不断循环,热点分离可以解决这个问题。有点类似concurrenthashmap,分而治之。

(2)completableFuture 对Future进行增强,支持函数式编程的流式调用。提供更多功能,压缩编码量。

(3)stampedLock 改进读写锁,读不阻塞写。如果读的时候,发生了写,应该重新读,不是阻塞写。解决了一般读写锁读太多导致写一直阻塞的问题,读线程发现数据不一致时触发重新读操作。 原理是维护了一个stamp标记,在添加写锁的释放写锁的时候,stamp都会改变(比如++),代码在加读锁的时候,可以先得到stamp,读完数据释放读锁的时候,调用validate方法,检验刚才stamp和现在stamp是否相同,如果相同,说明读的过程中没有修改,读取成功,如果不相同,则说明读的时候发生了写,那么接下来两种策略,一个是继续用当前stamp为初试,继续读,读完比较stamp,是乐观的办法;另一种直接调用readlock(),升级为正常的读锁,是悲观办法。

并发设计模式和锁优化以及jdk8并发新特性的更多相关文章

  1. Java学习:JDK8的新特性

    Java学习:JDK8的新特性 一.十大特性 Lambda表达式 Stream函数式操作流元素集合 接口新增:默认方法与静态方法 方法引用,与Lambda表达式联合使用 引入重复注解 类型注解 最新的 ...

  2. java 28 - 7 JDK8的新特性 之 接口可以使用方法

    JDK8的新特性: http://bbs.itcast.cn/thread-24398-1-1.html 其中之一:接口可以使用方法 interface Inter { //抽象方法 public a ...

  3. JDK8.0新特性

    连接转载地址:http://www.2cto.com/kf/201609/544044.html Eclipse: http://aiyiupload.oss-cn-beijing.aliyuncs. ...

  4. JDK8的新特性——Lambda表达式

    JDK8已经发布快4年的时间了,现在来谈它的新特性显得略微的有点“不合时宜”.尽管JDK8已不再“新”,但它的重要特性之一——Lambda表达式依然是不被大部分开发者所熟练运用,甚至不被开发者所熟知. ...

  5. JDK8之新特性扩展篇

    之前分篇章讲了一些JKD8中添加的新特性,还有一些新特性这里也一并讲下. BASE64 base64编码解码已经被加入到了jdk8中了. import java.nio.charset.Standar ...

  6. JDk8的新特性-流和内部iteration

    JDK8到今天已经出了好几年了  但是在公司能用到新特性的地方还是很少, 去年的时候当时项目老大要求我们用最新的写法来写Java 刚开始看到用stream写出来的代码一脸懵逼,内心就在想  这是Jav ...

  7. jdk8的新特性 Lambda表达式

    很多同学一开始接触Java8可能对Java8 Lambda表达式有点陌生. //这是一个普通的集合 List<Employee> list = em.selectEmployeeByLog ...

  8. JDK15就要来了,你却还不知道JDK8的新特性!

    微信搜「烟雨星空」,白嫖更多好文. 现在 Oracle 官方每隔半年就会出一个 JDK 新版本.按时间来算的话,这个月就要出 JDK15 了.然而,大部分公司还是在使用 JDK7 和 8 . 之前去我 ...

  9. Oracle12c中性能优化&amp;功能增强新特性之全局索引DROP和TRUNCATE 分区的异步维护

    Oracle 12c中,通过延迟相关索引的维护可以优化某些DROP和TRUNCATE分区命令的性能,同时,保持全局索引为有效. 1.   设置 下面的例子演示带全局索引的表创建和加载数据的过程. -- ...

随机推荐

  1. c的详细学习(6)函数

        根据模块化程序设计的原则,一个较大的程序一般要分为若干个小模块,每个模块实现一个比较简单的功能.在c语言中,函数是一个基本的程序模块.     (1)函数的基本概念: 1)基本介绍: 任何一个 ...

  2. python 3 mysql 索引原理与慢查询优化

    python 3 mysql 索引原理与慢查询优化 一 介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最 ...

  3. 【Flask模板】宏的概念和基本使用

    # 宏:模板中的宏跟python中的函数类似,可以传递参数,但是不能有返回值,可以将一些经常用到的代码片段放到宏中,然后把一些不固定的值抽取出来当成一个变量.使用宏的时候,参数可以为默认值.相关示例代 ...

  4. hadoop集群增加新节点

    上次hadoop集群一块数据盘报警, 提交工单后维修人员更换硬盘 服务器是dell r720的, 8盘位, 蛋疼的是这些硬盘都是做的单盘raid1,维修人员说必须关机导入硬盘才能正常使用 (服务器就这 ...

  5. Spring Cloud之网关搭建

    统一由网关进行拦截判断 要不放到每个服务里面就很不合适了 冗余 主要的: <dependency> <groupId>org.springframework.cloud< ...

  6. sql 常用的查询套路

    1. 写一个sql:,查询商城每天的用户数及每天累计用户数   date        user_count  total_count2016-12-01    1            12016- ...

  7. java:maven中webapp下的jsp不能访问web-inf下面的bean

    java:maven中webapp下的jsp不能访问web-inf下面的bean 当然 WEB-INF下面的文件是不能访问的,只能吧jsp文件放入到WEB-INF下面,然后通过配置WEB-INF下we ...

  8. MVC中ajax调用Controller的方法

    1. ajax代码: $.ajax({ async: false, cache: false, type: 'POST', contentType: "application/json&qu ...

  9. 分享知识-快乐自己:解决 Maven 无法下载 fastdfs-client-java 依赖。

    因为fastdfs-client-java-1.27-SNAPSHOT.jar这个依赖包在maven中央仓库是没有的. 需要自己编译源码成jar本地安装到maven 的本地仓库,安装完以后就能正常引用 ...

  10. C++(三)— 二维容器

    1.二维bool向量 vector<vector<bool>> dp(len, vector<bool>(len, false));