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. 第12条:不要在for和while循环后面写else块

    核心知识点: (1)一般的if/else是前面不执行,后面才执行,循环下面的else是前面执行完后面才会执行,如果是break打断也不会执行.循环为空或False也不执行. (2)try/expect ...

  2. HDU - 5550 Game Rooms 【DP+前缀和】

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5550 题意 一撞大楼有N层楼,然后每层楼都有一部分人喜欢打羽毛球,一部分人喜欢打乒乓球 但是每层楼只能 ...

  3. 【leetnode刷题笔记】Maximum Depth of binary tree

    Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...

  4. django 之admin后台管理

    数据库 from django.db import models from django.contrib.auth.models import User from django.contrib.aut ...

  5. 关于使用unigui、webxone、mysql的几个问题

    一.webxone的问题:1.目前稳定可用的版本好像是v2510:2.设计webxone应用时,窗口的“position”属性只能设置为poDesigned,而且不能动态改变窗口尺寸,否则在浏览器中显 ...

  6. 关于 tornado.simple_httpclient SimpleAsyncHTTPClient fetch下载大文件,默认60s的问题

    遇到了线上发布任务失败的情况,要发布的包大小77M,网络OK,手动测试速度是1.7M,下载77M文件用时17s左右,理论上完全没有问题 但是,从日志看确实是download的时候,60s 超时了,而且 ...

  7. APP被应用商店下架了怎么办?

    上周五的时候,知乎被各大APP应用商店下架,原因是因为在应用内一些信息不符合相关的规定所以被强制性下架,看起来只是简单的一个应用被下架的事情.但是作为一个推广人员,我第一件事情想到的是,假如我自己公司 ...

  8. PHP继承中$this的问题

    在父类中的构造函数中使用$this , 这是$this指的是正在实例化的子类对象,不管是parent还是继承调用父类的构造函数. 如: class CompanyController extends ...

  9. 图数据库Neo4j简介

    图数据库Neo4j简介 转自: 图形数据库Neo4J简介 - loveis715 - 博客园https://www.cnblogs.com/loveis715/p/5277051.html 最近我在用 ...

  10. MySQL--Basic(二)

    USE db_name; CREATE DATABASE school; Use school; CREATE TABLE `StuInfo` ( `STU_ID` ) NOT NULL , `STU ...