因此强烈怀疑是java序列化机制导致问题由于weblogic/ejb的类太复杂不方便测试因此单独写了个类来模拟这种场景:
1. 有大量线程在运行期间都有序列化操作
2. 被序列化对象比较大有大量子对象(子对象子对象...)
运行测试代码问题重现测试用开了50个线程thread dump并分析thread dump信息发现49个线程处于waiting 状态只有个线程在干活!因此抛开weblogic/ejb单独分析java序列化机制首先看thread dump线程信息:
占有锁线程:
"testthread21" prio=6 tid=0x0ad2d3b8 nid=0x224 runnable [0x0b48f000..0x0b48fce4]
at java.io.ObjectStreamClass.processQueue(Unknown Source)
at java.io.ObjectStreamClass.lookup(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at java.util.ArrayList.writeObject(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at test.Test.test(Test.java:68)
at test.Test.run(Test.java:53)
at java.lang.Thread.run(Unknown Source)
等待加锁线程的:
"testthread49" prio=6 tid=0x0ad9a508 nid=0xa9c waiting for monitor entry [0x0bb8f000..0x0bb8fbe4]
at java.lang.ref.ReferenceQueue.poll(Unknown Source)
- waiting to lock <0x02fb1d40> (a java.lang.ref.ReferenceQueue$Lock)
at java.io.ObjectStreamClass.processQueue(Unknown Source)
at java.io.ObjectStreamClass.lookup(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at java.util.ArrayList.writeObject(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at test.Test.test(Test.java:68)
at test.Test.run(Test.java:53)
at java.lang.Thread.run(Unknown Source)
可以发现问题发生在类java.io.ObjectStreamClass中思路方法processQueue思路方法中:
void processQueue(ReferenceQueue<Class<?>> queue,
ConcurrentMap<? extends
WeakReference<Class<?>>, ?> map)
{
Reference<? extends Class<?>> ref;
while((ref = queue.poll) != null) {
map.remove(ref);
}
}
这里queue.poll有加锁继续跟进poll代码:
public Reference<? extends T> poll {
(queueEmpty) null;
synchronized (lock) {
reallyPoll;
}
}
可以看到通过synchronized 关键字在lock对象有加锁操作和thread dump信息相符看来问题就在这里了
开始分析了首先看现象“50个线程1个进入synchronized 块获得锁49个在试图加锁而处于waiting状态”首先想到是synchronized块中代码执行时间比较长造成锁长时间处于被占有状态其他线程只能等但是查看reallyPoll思路方法发现它实现非常简单执行应该非常快后面profile信息也证实了这点
profile统计信息:
method num calls cumulative time mothod time percentage1 percentage2
thread=1
invokeWriteObject 387 30209 2
lookup 774778 17499 6605 57.9%
processQueue 774778 5523 2185
poll 774786 3338 2294 7.59%
reallyPoll 774793 1045 1045
thread=2
invokeWriteObject 739 59715 3
lookup 1479482 34550 12815 57.85%
processQueue 1479482 11878 4236
poll 1479490 7642 5656 9.47%
reallyPoll 1479497 1987 1987
thread=5
invokeWriteObject 721 147203 3
lookup 1443446 99665 24631 67.7%
processQueue 1443446 58211 7044
poll 1443454 51167 49196 51.33%
reallyPoll 1443461 1971 1971
thread=50
invokeWriteObject 701 1438319 3
lookup 1403406 1369971 228508 95.24%
processQueue 1403406 1125351 6801
poll 1403414 1118550 1116462 77.62%
reallyPoll 1403421 2089 2089
注释:
num calls = number of methed calls
percentage1=lookup cumulative time / invokeWriteObject cumulative time
percentage2=poll mothod time / invokeWriteObject cumulative time
注意:当我们序列化个Data对象例子时这个例子里面带有个包含1000个DataItem例子ArrayList而每个DataItem例子有个和个String所以当invokeWriteObject思路方法被次时思路方法lookup/processQueue/poll/reallyPoll将被2000次同样等待锁加持锁和释放锁操作也要执行2000次虽然真正业务思路方法reallyPoll执行非常快
可以看到当线程增加时percentage1、percentage2变化已经可以介绍说明问题因此最后我给出我见解:
1. java序列化是cpu依赖型
2. synchronized lock严重影响java序列化
最新评论