改善性能意味着用更少的资源作更多的事情。为了利用并发来提升系统性能,咱们须要更有效的利用现有的处理器资源,这意味着咱们指望使 CPU 尽量出于忙碌状态(固然,并非让 CPU 周期出于应付无用计算,而是让 CPU 作有用的事情而忙)。若是程序受限于当前的 CPU 计算能力,那么咱们经过增长更多的处理器或者经过集群就能提升总的性能。总的来讲,性能提升,须要且仅须要解决当前的受限资源,当前受限资源多是:java
若是你的系统有以下的特色,说明系统存在性能瓶颈:算法
随着系统逐步增长压力,CPU 使用率没法趋近 100%(以下图)数据库
持续运行缓慢。时常发现应用程序运行缓慢。经过改变环境因子(负载,链接数等)也没法有效提高总体响应时间网络
一个好的程序,应该是可以充分利用 CPU 的。若是一个程序在单 CPU 的机器上不管多大压力都不能使 CPU 使用率接近 100%,说明这个程序设计有问题。一个系统的性能瓶颈分析过程大体以下:多线程
高性能在不一样的应用场合下,有不一样的含义:并发
性能调优的终极目标是:系统的 CPU 利用率接近 100%,若是 CPU 没有被充分利用,那么有以下几个可能:oracle
下面是一种常见的错误app
两个不相干的方法(没有使用同一个共享变量),共用了 this 锁,致使人为的资源竞争上面的代码将 synchronized 加在类的每个方法上面,违背了保护什么锁什么的原则。对于无共享资源的方法,使用了同一个锁,人为形成了没必要要的等待。Java 缺省提供了 this 锁,这样不少人喜欢直接在方法上使用 synchronized 加锁,不少状况下这样作是不恰当的,若是不考虑清楚就这样作,很容易形成锁粒度过大:socket
上面的代码应该变成下面数据库设计
单 CPU 场合 将耗时操做拿到同步块以外,有的状况下能够提高性能,有的场合则不能:上面的代码,会致使一个线程长时间占有锁,而在这么长的时间里其余线程只能等待,这种写法在不一样的场合下有不一样的提高余地:
无论如何,缩小同步范围,对系统没有任何很差的影响,大多数状况下,会带来性能的提高,因此必定要缩小同步范围,所以上面的代码应该改成
上面提到的这些缘由造成的性能瓶颈,均可以经过线程堆栈分析,找到根本缘由。
性能瓶颈的几个特征:
鉴于性能瓶颈的以上特色,进行性能模拟的时候,必定要使用比系统当前稍高的压力下进行模拟,不然性能瓶颈不会出现。具体步骤以下:
经过线程堆栈,能够很容易的识别多线程场合下高负载的时候才会出现的性能瓶颈。一旦一个系统出现性能瓶颈,最重要的就是识别性能瓶颈,而后根据识别的性能瓶颈进行修改。通常多线程系统,先按照线程的功能进行归类(组),把执行相同功能代码的线程做为一组进行分析。当使用堆栈进行分析的时候,以这一组线程进行统计学分析。若是一个线程池为不一样的功能代码服务,那么将整个线程池的线程做为一组进行分析便可。
通常一个系统一旦出现性能瓶颈,从堆栈上分析,有以下三种最为典型的堆栈特征:
一个例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
"Thread-243" prio=1 tid=0xa58f2048 nid=0x7ac2 runnable [0xaeedb000..0xaeedc480] at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(SocketInputStream.java:129) at oracle.net.ns.Packet.receive(Unknown Source) ... ... at oracle.jdbc.driver.LongRawAccessor.getBytes() at oracle.jdbc.driver.OracleResultSetImpl.getBytes() - locked <0x9350b0d8> (a oracle.jdbc.driver.OracleResultSetImpl) at oracle.jdbc.driver.OracleResultSet.getBytes(O) ... ... at org.hibernate.loader.hql.QueryLoader.list() at org.hibernate.hql.ast.QueryTranslatorImpl.list() ... ... at com.wes.NodeTimerOut.execute(NodeTimerOut.java:175) at com.wes.timer.TimerTaskImpl.executeAll(TimerTaskImpl.java:707) at com.wes.timer.TimerTaskImpl.execute(TimerTaskImpl.java:627) - locked <0x80df8ce8> (a com.wes.timer.TimerTaskImpl) at com.wes.threadpool.RunnableWrapper.run(RunnableWrapper.java:209) at com.wes.threadpool.PooledExecutorEx$Worker.run() at java.lang.Thread.run(Thread.java:595) "Thread-248" prio=1 tid=0xa58f2048 nid=0x7ac2 runnable [0xaeedb000..0xaeedc480] at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(SocketInputStream.java:129) at oracle.net.ns.Packet.receive(Unknown Source) ... ... at oracle.jdbc.driver.LongRawAccessor.getBytes() at oracle.jdbc.driver.OracleResultSetImpl.getBytes() - locked <0x9350b0d8> (a oracle.jdbc.driver.OracleResultSetImpl) at oracle.jdbc.driver.OracleResultSet.getBytes(O) ... ... at org.hibernate.loader.hql.QueryLoader.list() at org.hibernate.hql.ast.QueryTranslatorImpl.list() ... ... at com.wes.NodeTimerOut.execute(NodeTimerOut.java:175) at com.wes.timer.TimerTaskImpl.executeAll(TimerTaskImpl.java:707) at com.wes.timer.TimerTaskImpl.execute(TimerTaskImpl.java:627) - locked <0x80df8ce8> (a com.wes.timer.TimerTaskImpl) at com.wes.threadpool.RunnableWrapper.run(RunnableWrapper.java:209) at com.wes.threadpool.PooledExecutorEx$Worker.run() at java.lang.Thread.run(Thread.java:595) ... ... "Thread-238" prio=1 tid=0xa4a84a58 nid=0x7abd in Object.wait() [0xaec56000..0xaec57700] at java.lang.Object.wait(Native Method) at com.wes.collection.SimpleLinkedList.poll(SimpleLinkedList.java:104) - locked <0x6ae67be0> (a com.wes.collection.SimpleLinkedList) at com.wes.XADataSourceImpl.getConnection_internal(XADataSourceImpl.java:1642) ... ... at org.hibernate.impl.SessionImpl.list() at org.hibernate.impl.SessionImpl.find() at com.wes.DBSessionMediatorImpl.find() at com.wes.ResourceDBInteractorImpl.getCallBackObj() at com.wes.NodeTimerOut.execute(NodeTimerOut.java:152) at com.wes.timer.TimerTaskImpl.executeAll() at com.wes.timer.TimerTaskImpl.execute(TimerTaskImpl.java:627) - locked <0x80e08c00> (a com.facilities.timer.TimerTaskImpl) at com.wes.threadpool.RunnableWrapper.run(RunnableWrapper.java:209) at com.wes.threadpool.PooledExecutorEx$Worker.run() at java.lang.Thread.run(Thread.java:595)
"Thread-233" prio=1 tid=0xa4a84a58 nid=0x7abd in Object.wait() [0xaec56000..0xaec57700]
at java.lang.Object.wait(Native Method) at com.wes.collection.SimpleLinkedList.poll(SimpleLinkedList.java:104) - locked <0x6ae67be0> (a com.wes.collection.SimpleLinkedList) at com.wes.XADataSourceImpl.getConnection_internal(XADataSourceImpl.java:1642) ... ... at org.hibernate.impl.SessionImpl.list() at org.hibernate.impl.SessionImpl.find() at com.wes.DBSessionMediatorImpl.find() at com.wes.ResourceDBInteractorImpl.getCallBackObj() at com.wes.NodeTimerOut.execute(NodeTimerOut.java:152) at com.wes.timer.TimerTaskImpl.executeAll() at com.wes.timer.TimerTaskImpl.execute(TimerTaskImpl.java:627) - locked <0x80e08c00> (a com.facilities.timer.TimerTaskImpl) at com.wes.threadpool.RunnableWrapper.run(RunnableWrapper.java:209) at com.wes.threadpool.PooledExecutorEx$Worker.run() at java.lang.Thread.run(Thread.java:595) ... ... |
从堆栈看,有 51 个(socket)访问,其中有 50 个是 JDBC 数据库访问。其余方法被阻塞在 java.lang.Object.wait() 方法上。
减小锁的粒度,好比 ConcurrentHashMap 的实现默认使用 16 个锁的 Array(有一个反作用:锁整个容器会很费力,能够添加一个全局锁)
性能调优总有一个终止条件,若是系统知足以下两个条件,便可终止: