对于CPU而言,常见的瓶颈主要有两种:
服务器的压力很小,但是CPU的利用率却很高,这样的性能瓶颈相对比较容易定位(好比我只是说了你一句,你就哭了,你的弱点立马就暴露出来了);
给服务器施加的压力很大,但是CPU的利用率总是很低,也就是压力上不去,这类瓶颈最常见,定位起来也最困难(类似我对你用尽了各种手段,你就是不说实话,内心太强大了)。
影响压力上不去的因素很多,但是对于性能测试工程师而言,最具价值的瓶颈肯定是由于代码问题引起的了(定位到是代码问题导致的压力上不去,特有成就感),而导致这类问题出现的最常见的一个知识点,肯定就是锁了,如果对于Java多线程的锁机制不甚了解,分析定位代码的瓶颈和性能调优几乎是不可能的。
锁——确保多线程访问的数据一致性。
目前Java多线程的锁基本就是通过如下两种方式实现:
synchronized关键字
java.util.concurrent.locks包下的类(用的也蛮多,稍微有点复杂,课堂上讲吧)
今天就为大家分享synchronized关键字实现的加锁方式。
认识synchronized
假设这样一个场景,张三和李四都需要维修各自的电脑,但是只有一把螺丝刀工具,意味着同一时刻只能有一个人使用这把工具修他们的电脑,那么使用Java代码该如何实现呢?我们把张三和李四比喻成两个线程,把他们修电脑的过程用Java语言实现一下,开始!

上面代码执行后对线程做dump,摘取部分信息如下:

解读锁
wait()和sleep()
它们有一个共同点是,都会把当前的线程阻塞住( 时长为函数参数指定的时间), 我们称之为睡眠或者等待。但二者实际上是完全不同的两个函数, 二者有着最为本质的区别:
wait()  当线程执行到wait()方法上, 当前线程会释放监视锁, 此时其它线程可以占有该锁,一旦wait()方法执行完成, 当前线程又继续尝试获取该锁, 直到执行完该锁的作用域。 可以说wait()是多线程场合下用得最多的一个方法。 结合notify(),可以实现两个线程之间的通信,一个线程可以通过这种方法通知另一个线程继续执行, 完成线程之间的配合。 wait()和锁的示意图如下:

在wait(5000)这5秒( 5000毫秒) 期间, 当前线程会释放它占有的锁, 此时其它线程有机会获得该锁。 当wait(5000)执行完成后, 当前线程继续获得该锁的使用权。 满足如下条件之一, wait()方法退出:
达到了等待的时间之后, 自动退出。 如wait(5000),5秒后wait方法退出。
其它的线程调用了该锁的notify()方法。 如果多个线程在等待同一个锁, 只有一个线程会被通知到。
sleep()  与锁操作无关, 如果该方法恰好在一个锁的保护范围之内, 当前线程即使在执行sleep()的时候, 仍然继续保持监视锁。 该方法实际上仅仅是完成等待或者睡眠的语义。 示意图如下:

从上面的代码Thread.sleep(5000)可以看出, sleep()方法并不是锁上面的一个方法, 而是线程的一个静态方法。 也就是说该方法实际上是和锁操作无关的。 如果sleep()方法恰好在一个锁的保护范围之内, 那么当前线程即使执行到该sleep方法, 也不会产生特别的锁操作(持有锁或者释放锁), 如果原来持有, 现在仍然持有。 如果原来没有持有, 那么现在仍然不持有。
还记得第六篇文章解读的线程堆栈吗?包含的直接信息有:
线程的个数、 每个线程调用的方法堆栈、 当前锁的状态。 线程的个数可以直接数出来; 线程调用的方法堆栈, 从下向上看,即表示当前的线程调用了哪个类上的哪个方法。 而锁的状态看起来稍微有一点技巧。 与锁相关的三个重要信息如下:
当一个线程占有一个锁的时候, 线程堆栈中会打印—locked <0x24a23208>
当一个线程正在等待其它线程释放该锁, 线程堆栈中会打印—waiting to lock <0x24a23208>
当一个线程占有一个锁, 但又执行到该锁的wait()上, 线程堆栈中首先打印locked,然后又会打印—waiting on <0x24a23208>
源码:




运行上面的程序,打印堆栈信息如下:



从上面这个例子中, 可以很清晰地看出, 在线程堆栈中与锁相关的三个最重要的特征字:locked,waiting to lock,waiting on;了解这三个特征字, 就能够对锁进行分析了。
一般情况下, 当一个(些)线程在等待一个锁时, 应该有一个线程占用这个锁, 即如果有的线程在等待一个锁, 该锁必然被另一个线程占有了, 也就是说, 从打印的堆栈中如果能看到waiting to lock <0x04d02238>,应该也应该能找到一个线程locked <0x04d02238>。

Java项目性能瓶颈分析及定位(八)——Java线程堆栈分析(五)的更多相关文章

  1. Java问题定位之Java线程堆栈分析

    采用Java开发的大型应用系统越来越大,越来越复杂,很多系统集成在一起,整个系统看起来像个黑盒子.系统运行遭遇问题(系统停止响应,运行越来越慢,或者性能低下,甚至系统宕掉),如何速度命中问题的根本原因 ...

  2. Java线程堆栈分析

    不知觉间工作已有一年了,闲下来的时候总会思考下,作为一名Java程序员,不能一直停留在开发业务使用框架上面.老话说得好,机会是留给有准备的人的,因此,开始计划看一些Java底层一点的东西,尝试开始在学 ...

  3. 【转】java线上程序排错经验2 - 线程堆栈分析

    前言 在线上的程序中,我们可能经常会碰到程序卡死或者执行很慢的情况,这时候我们希望知道是代码哪里的问题,我们或许迫切希望得到代码运行到哪里了,是哪一步很慢,是否是进入了死循环,或者是否哪一段代码有问题 ...

  4. Java项目性能瓶颈定位

    文章目标 当Java项目出现性能瓶颈的时候,通常先是对资源消耗做分析,包括CPU,文件IO,网络IO,内存:之后再结合相应工具查找消耗主体的程序代码.本文主要介绍系统资源消耗的分析过程,以及常用的Ja ...

  5. jenkins构建java项目找不到命令mvn,java的解决方法

    jenkins构建java项目时出现的报错情况: $ mvn clean install FATAL: command execution failed java.io.IOException: er ...

  6. GitHub Java项目推荐|功能丰富的 Java 工具包|提高开发效率

    GitHub Java项目推荐|功能丰富的 Java 工具包|提高开发效率 功能丰富的 Java 工具包.它帮助我们实现了常用的工具方法,从而减少代码的体积,提高开发效率.该项目最初是作者工作项目中的 ...

  7. Github优秀java项目集合(中文版) - 涉及java所有的知识体系

    Java资源大全中文版 我想很多程序员应该记得 GitHub 上有一个 Awesome - XXX 系列的资源整理.awesome-java 就是 akullpp 发起维护的 Java 资源列表,内容 ...

  8. JAVA项目之苹果IAP内购JAVA服务器验证流程详解

    1.前言 本博客是经历过多个项目检验的, 绝对真实, 适应于对苹果iap内购稍微有些了解的JAVA开发人员,  认真看,  定能完美解决苹果内购问题. 苹果IAP内购支付实际上是"将客户端支 ...

  9. Java应用性能瓶颈分析思路

    1 问题描述 因产品架构的复杂性,可能会导致性能问题的因素有很多.根据部署架构,大致的可以分为应用端瓶颈.数据库端瓶颈.环境瓶颈三大类.可以根据瓶颈的不同部位,选择相应的跟踪工具进行跟踪分析. 应用层 ...

随机推荐

  1. ueditor chrome bug

    一.概述: 关于UEditor在谷歌浏览Chrome打开选择指上传图片,发现[点击选择图片]时无法立即弹出选择框,而是等4-7秒钟才显示出来的BUG,试了N多方法,改层级都用了,也无效.在网上找到了一 ...

  2. github 第三方登录

    第三方登录先了解 OAuth 2.0 OAuth 协议的认证和授权的过程如下: 用户打开我的博客后,我想要通过GitHub获取改用户的基本信息 在转跳到GitHub的授权页面后,用户同意我获取他的基本 ...

  3. chkconfig命令详细介绍

    命令介绍 chkconfig命令用来更新.查询.修改不同运行级上的系统服务.比如安装了httpd服务,并且把启动的脚本放在了/etc/rc.d/init.d目录下,有时候需要开机自动启动它,而有时候则 ...

  4. python 之django (一) Windows环境下Django 1.6.11开发环境搭建(简易版)

    转自 https://www.cnblogs.com/kkddij/p/4397163.html 需要安装如下部件: python 2.6.6 pip(最新版即可) Django 1.6.11 PyC ...

  5. 使用 Fetch完成AJAX请求

    使用 Fetch完成AJAX请求 写在前面 无论用JavaScript发送或获取信息,我们都会用到Ajax.Ajax不需要刷新页面就能发送和获取信息,能使网页实现异步更新. 几年前,初始化Ajax一般 ...

  6. JavaSE---死锁

    1.死锁: 当2个线程互相等待对方释放  同步监视器  时就会发生死锁,JVM没有监测,也没有采取任何措施来避免死锁(当出现死锁时,整个程序既不会发生任何异常,也不会有任何提示, 所有线程处于阻塞状态 ...

  7. java 各进程功能java,javac,javaw,javaws,javap

    javac 代码编译成字节码 javap字节码解析成代码 java.exe用于启动window console  控制台程序 javaw.exe用于启动 GUI程序 javaws.exe用于web程序 ...

  8. C语言有GetOpenFile吗?

    windows中有个GetOpenFile的函数,就是上面那个啦!!我们怎么来实现呢?要我用C语言写出来我真的跪了..但是我们可以输入文件的[绝对路径],配合fopen函数来实现的.. 注意问题 ①文 ...

  9. [转]IE和FireFox中JS兼容之event .

    转载于:http://blog.csdn.net/jiachunfeng/article/details/6448186 http://justcoding.iteye.com/blog/587876 ...

  10. SharePreferences的用法

    1.创建 sharepreferences的方法: 首先创建该对象: 例如:(注意现在后面的模式7.0可以使用的只有 MODE_PRIVATE,其他全过时了 ) SharedPreferences s ...