当前位置:天才代写 > tutorial > JAVA 教程 > 分解java.util.concurrent锁

分解java.util.concurrent锁

2017-11-11 08:00 星期六 所属: JAVA 教程 浏览:771

副标题#e#

1. 导言

措施的机能阐明是应用措施开拓进程中的一个重要方面。这个事情一般是由一些专业人员来完成的,他们的方针是在一个特定的平台上,提高代码的机能。当措施是运行在多核平台的多线程可能并行措施的时候,提高机能这个问题就变得越发坚苦了。因为在这样的环境下,不只需要思量代码的机能,还需要思量代码的可伸缩性。

跟着Java 5中引入了java.util.concurrent (JUC)包,在Java语言中呈现了一种新的锁。JUC包利用得越来越普遍,因为更多的应用措施需要为了多核系统而开拓或仔细地调优。固然JLM可以找到传统的Java锁的具体的竞争信息,可是却没有同样的东西可以或许找到java.util.concurrent.locks包的锁竞争信息。 Sun/Oracle、IBM,尚有其他Java厂商也都没有这样的东西。缺乏对JUC锁的分解东西正是我们开拓这个锁东西,jucprofiler(Multicore SDK的一部门)的念头。

2. jucprofiler概览

当在措施中利用JUC锁的时候,线程会在下面两种环境下“遏制”执行:

当线程A试图去得到一个JUC锁,但这个锁却已经被别的一个线程得到,那么线程A不得不“遏制”,直到这个锁被释放可能超时。

当线程A挪用了java.util.concurrent.locks.Condition的任意一个“期待”的API,线程A会遏制执行,直到别的一个线程通知它可能超时。

我们别离把这两种环境称作“锁竞争时间”和“期待时间”。

jucprofiler就是为了捕捉以上两种环境的时间开销而设计和实现的。

2.1. 代码修改(Instruments)

为了获取JUC锁的运行时数据,需要提前修改一些JUC类,然后替换掉JRE中相应的类。在首次利用jucprofiler之前,用户需要运行呼吁去生成PreInstrument.jar。假设JRE没有改变的话,这个步调只需要做一次。(假如用户改变了JRE,那么用户需要本身删除 PreInstrument.jar,然后从头运行这个呼吁,来再次生成PreInstrument.jar)。

解析java.util.concurrent锁

2.1.1. 锁竞争时间开销

对付锁竞争时间开销,jucprofiler记录了申请类 java.util.concurrent.locks.AbstractQueuedSynchronizer 和类java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject的实例,而且给这些实例分派独一的标识。

要领 挪用位置
java.util.concurrent.locks.LockSupport park (Object); 类AbstractQueuedSynchronizer中的要领parkAndCheckInterrupt()
  parkNanos(Object blocker, long nanos) 类AbstractQueuedSynchronizer中的要领doAcquireNanos(int arg, long nanosTimeout)与doAcquireSharedNanos(int arg, long nanosTimeout)

2.1.2. 锁期待时间开销

对付锁期待时间开销,jucprofiler获取了在差异的位置挪用类java.util.concurrent.locks.LockSupport的要领park(blocker)与parkNanos(blocker, nanos)的时间开销:

要领 挪用位置
java.util.concurrent.locks.LockSupport park (Object); 类 AbstractQueuedSynchronizer除parkAndCheckInterrupt()以外的要领
  parkNanos(Object blocker, long nanos) 类AbstractQueuedSynchronizer除doAcquireNanos(int arg, long nanosTimeout)与doAcquireSharedNanos(int arg, long nanosTimeout) 以外的要领


#p#副标题#e#

3. 如何利用

本节将通过一个真实的应用来探究如何利用jucprofiler来寻找措施中的问题。

3.1. 运行jucprofiler

利用如下的呼吁:

$ java -Xbootclasspath/p:$JUCP/BCIRuntime.jar:$JUCP/PreInstrument.jar
  -javaagent:$JUCP/BCIAgent.jar=callStackDepth=10:allocationStackDepth=0
:,msdk.idp=com.ibm.msdk.bciagent.JUCInstrumentDecisionProvider,:libPath=$JUCP:traceJUC=on
  -cp .:derby.jar JavaDBDemo 

jucprofiler可以用于任何运行在JDK6上的Java措施上。假设jucprofiler安装在了目次$JUCP中,在 jucprofiler运行完你的措施之后,就会生成一个叫"BCIAgent.***.bci.trace"的文件,个中"***"代表本次运行的独一时间戳。

3.2. 获取功效

运行如下所示的呼吁来获得功效:

$ java -Xmx1000m -jar $JUCP/BCITraceReader.jar {tracefile} {resultOutputFile} 

个中:

{tracefile}是一个追踪文件的全路径名称可能是一个包括若干追踪文件的目次名称,好比BCIAgent.***.bci.trace。

{resultOutputFile}是可选的参数,用来指定存放阐明功效的文件。假如没有这个选现,那么阐明功效就会在节制台打印出来。

#p#分页标题#e#

说明:因为对追踪文件过后阐明进程会有一些内存开销,所以最好用Java选项-Xmx来增加堆的巨细。在我们的尝试里,阐明160M的文件,需要800M的内存。

3.3. 功效理会

如下图所示,纯文本输出包括了差异范例的信息,好比锁的名称,锁竞争的次数和时间,锁被持有的时间和次数,锁在申请时线程的挪用栈,一连的时间和每一次锁竞争的挪用栈。这些功效有助于用户发明JUC锁竞争造成的措施瓶颈。

在“LEGEND” 段之前,功效陈诉首先,凭据锁竞争次数和时间的降序,总结了措施中全部的JUC锁竞争。个中每一行属于两种范例的一种,“AQS”代表JUC 锁,“CHM”代表ConcurrentHashMap.  因为一个ConcurrentHashMap内部被支解为了若干个片断(segment)举办存储,并且每一个片断都被一个差异的JUC锁掩护,所以,从锁的角度来看,ConcurrentHashMap可以被看作为一个JUC锁的荟萃。譬喻,“CHM@8”有276次锁竞争,一共3,945,7000 纳秒的竞争时间,这就是说,“CHM@8”中的所有片断的JUC锁共有276次锁竞争,一共3,945,7000纳秒的竞争时间。这样的对锁的分组可以或许辅佐措施员发明哪一个ConcurrentHashMap工具产生了最严重的锁竞争。相反,JUC锁“AQS@1790” 不属于任何一个ConcurrentHashMap工具,它就是措施中一个显式利用的锁。

说明:因为在这个例子中,没有打开记录得到锁的成果,所以列HOLD-COUNT和HOLD-TIME都是零。

在“LEGEND”段之后,功效给出了每一个JUC锁竞争的具体信息。在下边的功效片断中,对付ConcurrentHashMap “CHM@8” ,锁竞争呈此刻两个用来掩护片断的锁上 “Lock [AQS@135]” and “Lock [AQS@146]”。对付“Lock [AQS@135]”,它在一个措施位置呈现竞争,显示了竞争的次数,时间和竞争时刻的线程挪用栈。对付“Lock [AQS@146]”,给出了同样的信息。这些细节信息可以很好地辅佐措施员来定位措施中的锁竞争,而且清楚地领略ConcurrentHashMap中哪个片断竞争最严重。

Multicore Software Development Toolkit Version_2.1

j.u.c Lock Profiler Report

         NAME  CONTD-COUNT     CONTD-TIME   HOLD-COUNT      HOLD-TIME
         CHM@8      276      39457000       0          0
       AQS@1790       36       4029000       0          0
        AQS@131       17       630000       0          0
=================================================================================================
  LEGEND:
         NAME : Name of juc lock(AQS) or ConcurrentHashMap(CHM), format: <Type>@<Idgt;
      CONTD-COUNT : Total count of lock contention
      CONTD-TIME : Total time of lock contention in nanosecond
      HOLD-COUNT : Total count of lock hold
       HOLD-TIME : Total time of lock hold in nanosecond
================================================================================================== 

ConcurrentHashMap [CHM@8]:

-----------------------------------------------------------------------------------------------------------
Lock [AQS@135]:

-----------------------------------------------------------------------------------------------------------
Lock Contention 1 
CONTD-COUNT: 25
CONTD-TIME: 10827000
Call Stack:
java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:758)
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:789)
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1125)
java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:197)
java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:273)
java.util.concurrent.ConcurrentHashMap$Segment.remove(ConcurrentHashMap.java:530)
java.util.concurrent.ConcurrentHashMap.remove(ConcurrentHashMap.java:934)
org.apache.derby.impl.services.locks.ConcurrentLockSet.unlock(ConcurrentLockSet.java:740)
org.apache.derby.impl.services.locks.ConcurrentLockSet.unlockReference(ConcurrentLockSet.java:784)
org.apache.derby.impl.services.locks.LockSpace.unlockReference(LockSpace.java:275)

Lock [AQS@146]:

-----------------------------------------------------------------------------------------------------------
Lock Contention 1 
CONTD-COUNT: 22
CONTD-TIME: 2009000
Call Stack:
java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:758)
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:789)
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1125)
java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:197)
java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:273)
java.util.concurrent.ConcurrentHashMap$Segment.remove(ConcurrentHashMap.java:530)
java.util.concurrent.ConcurrentHashMap.remove(ConcurrentHashMap.java:934)
org.apache.derby.impl.services.locks.ConcurrentLockSet.unlock(ConcurrentLockSet.java:740)
org.apache.derby.impl.services.locks.ConcurrentLockSet.unlockReference(ConcurrentLockSet.java:784)
org.apache.derby.impl.services.locks.LockSpace.unlockReference(LockSpace.java:275)

#p#副标题#e#

3.4. 在可视化阐明器中打开追踪文件

#p#分页标题#e#

可视化阐明器,作为multicore SDK的一部门,提供了一些Eclipse视图,可以用表格和图表来显示jucprofiler文件。当前有两个视图,一个叫“J.U.C 统计”视图,别的一个叫“J.U.C 同步”视图。

“J.U.C 统计”视图如下所示。右边的两列是“竞争时间”和“竞争次数”。“申请栈”是关于JUC锁在申请的时候的挪用位置。

解析java.util.concurrent锁

“J.U.C 同步”视图如下所示。第一列是时间,表白什么时候锁呈现了竞争。第二列是线程,表白锁竞争产生哪个线程。第三列是锁,表白谁人JUC锁呈现竞争了。最后一列是要领,表白锁竞争是在什么位置产生的。

解析java.util.concurrent锁

3.5. 在线节制

在执行的进程中,jucprofiler会建设一个“节制处事器”监听2009端口。用户可以利用“节制客户端”毗连这个端口,节制jucprofiler的行为,好比,可以动态打开可能封锁追踪成果:

$ java -cp BCIRuntime.jar

com.ibm.msdk.bciruntime.control.ControlClient HOST -m [b|i] –b

START -e END

个中:

HOST:“节制客户端”要去毗连的主机名称,缺省是本机。

-m [b|i]: “节制客户端”执行的模式。- b是批处理惩罚模式、- i是交互模式。缺省是交互模式。

-b START:假如是批处理惩罚模式,START是开始分解的时间。

-e END:END是分解进程的一连时间。

3.5.1. 交互模式

有一个简朴的shell,用户可以输入一些呼吁juc.on和juc.off来打开和封锁jucprofiler。好比,java -cp BCIRuntime.jar com.ibm.msdk.bciruntime.control.ControlClient, “节制客户端” 会毗连到本机, 而且打开一个shell来节制jucprofiler.

$ java -cp BCIRuntime.jar com.ibm.msdk.bciruntime.control.ControlClient
jucprofiler control> juc.on
juc.on
jucprofiler t control> start
start
jucprofiler control> stop
stop
jucprofiler control> juc.off
juc.off
jmit control> quit
quit

$ java -cp BCIRuntime.jar com.ibm.msdk.bciruntime.control.ControlClient localhost -m b -b 2 -e 10
Start tracing in 2 seconds
Start tracing
Stop tracing in 10 seconds
Stop tracing
quit

3.5.2. 批处理惩罚模式

jucprofiler也支持批处理惩罚模式。好比, java -cp BCIRuntime.jar com.ibm.msdk.bciruntime.control.ControlClient mtrat-test.dyndns.org -m b -b 10 -e 10, 意思是 “节制客户端”会毗连到呆板mtrat-test.dyndns.org,10秒后启动jucprofiler,然后10秒后遏制 jucprofiler。

4. 结论

跟着多核处理惩罚器成为主流,更多的并行/多线程Java措施将不绝涌现。我们需要更好的东西去分解这些并行措施。本文先容的jucprofiler填补了Java机能阐明东西中的一个重要缺口。

 

    关键字:

天才代写-代写联系方式