多线程优化(性能调优)
目录
1.多线程基础
性能相关基础:
上下文切换:
2.多线程锁优化
2.1 案例
2.2 优化方案1--使用原子操作类AtomicXXX
2.2 LongAdder对象
3.多线程之并发容器优化
4.多线程之线程池优化
1.多线程基础
性能相关基础:
上下文切换:
无论是单核cpu还是多核cpu,都会有cpu时间片(分配给线程的运行时间),现在有两种情况:
- 线程1 运行完了
- 线程1 阻塞,挂起
当上述两种情况发生,就会发生上下文切换。上文:保存进度。下文:加载进度
上文:线程1 进度(执行进度信息,如执行完,执行了60%以后阻塞挂起)。
下文:线程2 进度(下一个线程执行信息,可能之前执行过,然后被唤醒)。
主频为1GHz的cpu执行一条cpu指令,耗时是1ns。一次上下文切换大约耗时8微秒=8000纳秒。
2.多线程锁优化
2.1 案例
先看这样一段代码:
public class LockTest {long count = 0;public void access(){count++;}public static void main(String[] args) throws InterruptedException {LockTest lockTest = new LockTest();for (int i=0;i<10;i++){new Thread(()->{for (int j=0;j<1000;j++){lockTest.access();}}).start();}Thread.sleep(5000);System.out.println(lockTest.count);}
}
该代码设置了10个线程,每个线程内对count执行1000次加一操作。由于线程安全问题,代码中打印的count的值一定是小于等于10000的。所以要对其进行优化。
2.2 优化方案1--使用原子操作类AtomicXXX
优化代码如下所示:
public class LockTest {// long count = 0;AtomicLong count = new AtomicLong();public void access(){count.incrementAndGet();}public static void main(String[] args) throws InterruptedException {LockTest lockTest = new LockTest();for (int i=0;i<10;i++){new Thread(()->{for (int j=0;j<1000;j++){lockTest.access();}}).start();}Thread.sleep(5000);System.out.println(lockTest.count);}
}
AtomicLong类中的部分代码如下所示。
private static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset; static {try {valueOffset = unsafe.objectFieldOffset(AtomicLong.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile long value;public final long incrementAndGet() {return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;}
这个value也就是上述代码中的count的值,在静态代码块中根据value获取count的内存偏移地址,然后将AtomicLong对象和value属性偏移地址传入unsafe.getAndAddLong()方法中,该方法代码如下所示:
public final long getAndAddLong(Object var1, long var2, long var4) {long var6;do {var6 = this.getLongVolatile(var1, var2);} while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));return var6;}
根据传入的AtomicLong对象和value偏移地址获取到value的值,赋值给var6,然后进行cas操作,具体百度cas原理。这里不再详细赘述。
基于cas实现的原子操作类,优势在哪?对比锁sync Lock。
没有上下文切换。假设一行java代码,cpu循环一次需要10ns,10个线程,按照平均法则分配cpu资源,10ns*10=100ns,
加锁10个线程,需要9次上下文切换,9*8微秒=72微秒=72000ns
总结:cas原子操作类 lock锁 sync锁
2.2 LongAdder对象
atomic还可以进一步优化么?如果是jdk8,推荐使用LongAdder对象,比AtomicLong性能更好(减少乐观锁的重试次数)
代码实现:
public class LockTest {// long count = 0;
// AtomicLong count = new AtomicLong(); //原子操作类LongAdder count = new LongAdder();public void access(){count.add(1);}public static void main(String[] args) throws InterruptedException {LockTest lockTest = new LockTest();for (int i=0;i<10;i++){new Thread(()->{for (int j=0;j<1000;j++){lockTest.access();}}).start();}Thread.sleep(5000);System.out.println(lockTest.count);}
}
atomicXXX和LongAdder的区别:分裂value,类似于分布式cas,分裂共享资源,最后累加。减少了乐观锁的自旋次数。
性能对比:
public class LongAdderTest {public static void main(String[] args) {testAtomicLongVSLongAdder(10,10000);testAtomicLongVSLongAdder(20,200000);testAtomicLongVSLongAdder(30,200000);}//多线程并发模拟及耗时统计private static void testAtomicLongVSLongAdder(final int threadcount, final int time) {try {long start = System.currentTimeMillis();testAtomicLong(threadcount,time);long end = System.currentTimeMillis()-start;System.out.println("Atomic-time:"+end);long start1 = System.currentTimeMillis();testLongAdder(threadcount,time);long end1 = System.currentTimeMillis()-start1;System.out.println("LongAdder-time:"+end1);}catch (InterruptedException e){e.printStackTrace();}}private static void testLongAdder(final int threadcount,final int time) throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(threadcount);LongAdder longAdder = new LongAdder();for (int i=0;i<threadcount;i++){new Thread(new Runnable() {@Overridepublic void run() {for (int j=0;j<time;j++){longAdder.add(1);}countDownLatch.countDown();}},"mythread"+i).start();}countDownLatch.await();}private static void testAtomicLong(final int threadcount,final int time) throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(threadcount);AtomicLong atomicLong = new AtomicLong();for (int i=0;i<threadcount;i++){new Thread(new Runnable() {@Overridepublic void run() {for (int j=0;j<time;j++){atomicLong.incrementAndGet();}countDownLatch.countDown();}},"mythread"+i).start();}countDownLatch.await();}}
运行结果:
10个线程数量,10000次数Atomic-time:4
10个线程数量,10000次数LongAdder-time:5
20个线程数量,200000次数Atomic-time:67
20个线程数量,200000次数LongAdder-time:28
30个线程数量,200000次数Atomic-time:76
30个线程数量,200000次数LongAdder-time:5
当线程数较少时(10个线程),LongAdder的分裂操作和最后加和操作耗费的时间相对于cas操作的时间来说就比较明显。优化效果不明显,因为LongAdder的分裂操作和加操作也会耗费一定的时间。
当线程数较多时,优化效果就很明显。
atomicXXX:强一致性
LongAdder:弱一致性
1、强一致性:在任何时刻所有的用户或者进程查询到的都是最近一次成功更新的数据。强一致性是程度最高一致性要求,也是最难实现的。关系型数据库更新操作就是这个案例。简而言之:就是操作完以后立刻拿到数据进行一致性核实。大厂高并发很少有强一致性!!!!!atomic在执行完cas操作以后就会立刻获取数据核实,因此是强一致性。
2、最终一致性:和强一致性相对,在某一时刻用户或者进程查询到的数据可能都不同,但是最终成功更新的数据都会被所有用户或者进程查询到。当前主流的nosql数据库都是采用这种一致性策略。LongAdder在执行完cas操作以后还要对各个结果进行求和以后才会核验一致性,因此是弱一致性。
锁优化过程:
3.多线程之并发容器优化
HashMap--->ConcurrentHashMap
ArrayList--->CopyOnWriteArrayList:适合于多读多写的场景。
实现原理:写时复制,当写入数据的时候,CopyOnWriteArrayList会先进行扩容操作,将老的数据复制到新的数组中。如果此刻有个读的线程来操作资源,当写线程还没完成时,则数组指针还是指向未扩容的老数组,故读的数据还是老数据。若此时写线程已经完成工作,则数组指针就会指向新的数组,此时读到的数据是新的数据。
4.多线程之线程池优化
这些指标都存在与两个map中:
//线程池整个运行状态,存放多个runnableNameMap,key--task,value--runnableNameMap
public Map<String,Map> transactionMap = new ConcurrentHashMap<>();
//存储单个任务状态
public Map<String,String> runnableNameMap= new ConcurrentHashMap<>();
多线程优化(性能调优)相关推荐
- java多线程程序性能调优 优化过程
我, 一多年c++开发,由于项目原因需要对一个性能底下的多线程java程序进行调优,百度google了几把,妈蛋,没有发现指导如何java线程调优的文章啊,都是一些java使用规范,我去,那我大jav ...
- Java程序性能优化——性能调优层次
为了提升系统性能,开发人员可以从系统的各个角度和层次对系统进行优化.除了最常见的代码优化外,在软件架构上.JVM虚拟机层.数据库以及操作系统层都可以通过各种手段进行调优,从而在整体上提升系统的性能. ...
- 网站高并发优化性能调优总结
最近在对PHP网站高并发高性能有所领悟,今天写一篇关于这方面的文章.今天用我的测试站点:http://zhimo.yuanzhumuban.cc/来讲解实例. 支模网整体开发到上线为10个月左右,后端 ...
- 《Java性能调优实战》笔记(一)Java编程性能调优、多线程性能优化
文章目录 一.Java性能调优概述 1.1 性能调优标准 1.2 制定性能调优策略 二.Java编程性能调优 2.1 字符串 2.2 正则表达式 2.3 ArrayList和LinkedList的选择 ...
- 性能调优之Java系统级性能监控及优化
性能调优之Java系统级性能监控及优化 对于性能调优而言,通常我们需要经过以下三个步骤:1,性能监控:2,性能剖析:3,性能调优 性能调优:通过分析影响Application性能问题根源,进行优化Ap ...
- 服务器优化:Tomcat、JVM性能调优笔记
找到Tomcat根目录下的conf目录,修改server.xml文件的内容.对于这部分的调优,我所了解到的就是无非设置一下Tomcat服务器的最大并发数和Tomcat初始化时创建的线程数的设置,当然还 ...
- 鲲鹏性能优化十板斧(二)——CPU与内存子系统性能调优
1.1 CPU与内存子系统性能调优简介 调优思路 性能优化的思路如下: l 如果CPU的利用率不高,说明资源没有充分利用,可以通过工具(如strace)查看应用程序阻塞在哪里,一般为磁盘,网络或应 ...
- MySQL性能调优与架构设计——第11章 常用存储引擎优化
第11章 常用存储引擎优化 前言: MySQL 提供的非常丰富的存储引擎种类供大家选择,有多种选择固然是好事,但是需要我们理解掌握的知识也会增加很多.每一种存储引擎都有各自的特长,也都存在一定的短处. ...
- 深扒,用 6 部分讲完 Java 性能调优:多线程 + 设计模式 + 数据库
Java 性能调优 Java 性能调优,是一个老生常谈的话题.可能有些人觉得没用,一些细小的地方没有好修改的,改与不改对于代码的运行效率有什么影响呢? Java 性能调优不单单是学一门编程语言那么简单 ...
- 第七篇:双管齐下,JVM内部优化与JVM性能调优
文章目录 一.前言 二.编译时优化 2.1 Javac编译器 2.2 Java语法糖 2.2.1 泛型和泛型擦除 2.2.2 自动装箱.自动拆箱.遍历循环 2.2.3 条件编译 三.运行时优化(核心: ...
最新文章
- 背景图像位置css_CSS背景图像大小教程–如何对整页背景图像进行编码
- IDEA使用log4j
- 对操作系统安全构成威胁的问题
- 开发日记-20190329
- Gstreamer基础知识介绍
- Kaggle入门 (Titanic TensorFlow Softmax)
- 双手无法敲代码的程序员,该如何编程?
- python sleep什么意思,Python sleep()
- 简单的nios II 流水灯 软件部分
- 一目了然,看民生银行 IT 运维故障管理可视化案例
- 稳住 稳住 。不要急!
- IDEA中集成使用SVN
- 个人MD风格博客系统(未完成)
- 轉載:2006中国大陆企业慈善捐赠100榜
- 什么是网站死链?如何查询网站死链?网站死链怎么解决?
- 在线头像制作网站FaceYourManga
- 阿里云心选“小眯眼摄像头”视频监控天猫精灵可控手机远程wifi高清
- 美团2020后台校招题目--美团骑手包裹区间分组
- RANSAC与其改进
- ORACLE 根据分组排序产生序列号
热门文章
- torch.autograd学习系列之torch.autograd.grad()函数学习
- string与string头文件
- siglow 造成的网卡驱动问题及驱动更新错误解决
- word-多标签工具Office Tab(自用+带下载地址)
- 医疗器械行业面经——美敦力
- python单步调试工具pdb
- 安妮股份(002235)副董事长黄清华:大数据将带来知识产权和版权价值评估新革命...
- LaTex写英文论文时 如何输入单引号、双引号、省略号,及其他特殊符号
- Python matplotlib.pyplot.hist函数 参数详解(超详细的!)
- ITSS怎么样?对IT行业企业有何意义?