Skip to content

Commit 4845b64

Browse files
carryxyhbeiwei30
authored andcommitted
New threadLocal provides more performance. (apache#1745)
* SerializerFactory 获取Serializer时,锁住整个hashmap,导致整个过程被block * 单元测试。保证一个class只有一个serializer和deserializer。单线程和多线程测试 * 增加线程数 50 模拟多个线程来获取serializer和deserializer * 当cores线程数全都使用的情况下,默认线程池会把任务放入到队列中。队列满则再创建线程(总数不会超过Max线程数) 增强线程池:在请求量阶段性出现高峰时使用 特性:cores线程全部使用的情况下,优先创建线程(总数不会超过max),当max个线程全都在忙的情况下,才将任务放入队列。请求量下降时,线程池会自动维持cores个线程,多余的线程退出。 * 当cores线程数全都使用的情况下,默认线程池会把任务放入到队列中。队列满则再创建线程(总数不会超过Max线程数) 增强线程池:在请求量阶段性出现高峰时使用 特性:cores线程全部使用的情况下,优先创建线程(总数不会超过max),当max个线程全都在忙的情况下,才将任务放入队列。请求量下降时,线程池会自动维持cores个线程,多余的线程退出。 * 补全单元测试,测试扩展是否生效 * 错误命名 * 增加@OverRide注解 long 初始化赋值时,小写l改为大写L防止误读 * 修复单元测试 * remove enhanced * remove enhanced * Faster ThreadLocal impl in internal use * Used in RpcContext`s LOCAL field. * Faster get than the traditional ThreadLocal * add License * fix ci failed * fix ci failed * fix ci failed * fix ci failed * fix ci failed * remove author info * fix destroy method * fix bug at method size.
1 parent d313d33 commit 4845b64

File tree

11 files changed

+678
-15
lines changed

11 files changed

+678
-15
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package com.alibaba.dubbo.common.threadlocal;
19+
20+
/**
21+
* InternalThread
22+
*/
23+
public class InternalThread extends Thread {
24+
25+
private InternalThreadLocalMap threadLocalMap;
26+
27+
public InternalThread() {
28+
}
29+
30+
public InternalThread(Runnable target) {
31+
super(target);
32+
}
33+
34+
public InternalThread(ThreadGroup group, Runnable target) {
35+
super(group, target);
36+
}
37+
38+
public InternalThread(String name) {
39+
super(name);
40+
}
41+
42+
public InternalThread(ThreadGroup group, String name) {
43+
super(group, name);
44+
}
45+
46+
public InternalThread(Runnable target, String name) {
47+
super(target, name);
48+
}
49+
50+
public InternalThread(ThreadGroup group, Runnable target, String name) {
51+
super(group, target, name);
52+
}
53+
54+
public InternalThread(ThreadGroup group, Runnable target, String name, long stackSize) {
55+
super(group, target, name, stackSize);
56+
}
57+
58+
/**
59+
* Returns the internal data structure that keeps the threadLocal variables bound to this thread.
60+
* Note that this method is for internal use only, and thus is subject to change at any time.
61+
*/
62+
public final InternalThreadLocalMap threadLocalMap() {
63+
return threadLocalMap;
64+
}
65+
66+
/**
67+
* Sets the internal data structure that keeps the threadLocal variables bound to this thread.
68+
* Note that this method is for internal use only, and thus is subject to change at any time.
69+
*/
70+
public final void setThreadLocalMap(InternalThreadLocalMap threadLocalMap) {
71+
this.threadLocalMap = threadLocalMap;
72+
}
73+
}
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package com.alibaba.dubbo.common.threadlocal;
19+
20+
import java.util.Collections;
21+
import java.util.IdentityHashMap;
22+
import java.util.Set;
23+
24+
/**
25+
* InternalThreadLocal
26+
* A special variant of {@link ThreadLocal} that yields higher access performance when accessed from a
27+
* {@link InternalThread}.
28+
* <p></p>
29+
* Internally, a {@link InternalThread} uses a constant index in an array, instead of using hash code and hash table,
30+
* to look for a variable. Although seemingly very subtle, it yields slight performance advantage over using a hash
31+
* table, and it is useful when accessed frequently.
32+
* <p></p>
33+
* This design is learning from {@see io.netty.util.concurrent.FastThreadLocal} which is in Netty.
34+
*/
35+
public class InternalThreadLocal<V> {
36+
37+
private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();
38+
39+
private final int index;
40+
41+
public InternalThreadLocal() {
42+
index = InternalThreadLocalMap.nextVariableIndex();
43+
}
44+
45+
/**
46+
* Removes all {@link InternalThreadLocal} variables bound to the current thread. This operation is useful when you
47+
* are in a container environment, and you don't want to leave the thread local variables in the threads you do not
48+
* manage.
49+
*/
50+
@SuppressWarnings("unchecked")
51+
public static void removeAll() {
52+
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
53+
if (threadLocalMap == null) {
54+
return;
55+
}
56+
57+
try {
58+
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
59+
if (v != null && v != InternalThreadLocalMap.UNSET) {
60+
Set<InternalThreadLocal<?>> variablesToRemove = (Set<InternalThreadLocal<?>>) v;
61+
for (InternalThreadLocal<?> tlv : variablesToRemove) {
62+
tlv.remove(threadLocalMap);
63+
}
64+
}
65+
} finally {
66+
InternalThreadLocalMap.remove();
67+
}
68+
}
69+
70+
/**
71+
* Returns the number of thread local variables bound to the current thread.
72+
*/
73+
public static int size() {
74+
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
75+
if (threadLocalMap == null) {
76+
return 0;
77+
} else {
78+
return threadLocalMap.size();
79+
}
80+
}
81+
82+
public static void destroy() {
83+
InternalThreadLocalMap.destroy();
84+
}
85+
86+
@SuppressWarnings("unchecked")
87+
private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, InternalThreadLocal<?> variable) {
88+
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
89+
Set<InternalThreadLocal<?>> variablesToRemove;
90+
if (v == InternalThreadLocalMap.UNSET || v == null) {
91+
variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<InternalThreadLocal<?>, Boolean>());
92+
threadLocalMap.setIndexedVariable(variablesToRemoveIndex, variablesToRemove);
93+
} else {
94+
variablesToRemove = (Set<InternalThreadLocal<?>>) v;
95+
}
96+
97+
variablesToRemove.add(variable);
98+
}
99+
100+
@SuppressWarnings("unchecked")
101+
private static void removeFromVariablesToRemove(InternalThreadLocalMap threadLocalMap, InternalThreadLocal<?> variable) {
102+
103+
Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
104+
105+
if (v == InternalThreadLocalMap.UNSET || v == null) {
106+
return;
107+
}
108+
109+
Set<InternalThreadLocal<?>> variablesToRemove = (Set<InternalThreadLocal<?>>) v;
110+
variablesToRemove.remove(variable);
111+
}
112+
113+
/**
114+
* Returns the current value for the current thread
115+
*/
116+
@SuppressWarnings("unchecked")
117+
public final V get() {
118+
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
119+
Object v = threadLocalMap.indexedVariable(index);
120+
if (v != InternalThreadLocalMap.UNSET) {
121+
return (V) v;
122+
}
123+
124+
return initialize(threadLocalMap);
125+
}
126+
127+
private V initialize(InternalThreadLocalMap threadLocalMap) {
128+
V v = null;
129+
try {
130+
v = initialValue();
131+
} catch (Exception e) {
132+
throw new RuntimeException(e);
133+
}
134+
135+
threadLocalMap.setIndexedVariable(index, v);
136+
addToVariablesToRemove(threadLocalMap, this);
137+
return v;
138+
}
139+
140+
/**
141+
* Sets the value for the current thread.
142+
*/
143+
public final void set(V value) {
144+
if (value == null || value == InternalThreadLocalMap.UNSET) {
145+
remove();
146+
} else {
147+
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
148+
if (threadLocalMap.setIndexedVariable(index, value)) {
149+
addToVariablesToRemove(threadLocalMap, this);
150+
}
151+
}
152+
}
153+
154+
/**
155+
* Sets the value to uninitialized; a proceeding call to get() will trigger a call to initialValue().
156+
*/
157+
@SuppressWarnings("unchecked")
158+
public final void remove() {
159+
remove(InternalThreadLocalMap.getIfSet());
160+
}
161+
162+
/**
163+
* Sets the value to uninitialized for the specified thread local map;
164+
* a proceeding call to get() will trigger a call to initialValue().
165+
* The specified thread local map must be for the current thread.
166+
*/
167+
@SuppressWarnings("unchecked")
168+
public final void remove(InternalThreadLocalMap threadLocalMap) {
169+
if (threadLocalMap == null) {
170+
return;
171+
}
172+
173+
Object v = threadLocalMap.removeIndexedVariable(index);
174+
removeFromVariablesToRemove(threadLocalMap, this);
175+
176+
if (v != InternalThreadLocalMap.UNSET) {
177+
try {
178+
onRemoval((V) v);
179+
} catch (Exception e) {
180+
throw new RuntimeException(e);
181+
}
182+
}
183+
}
184+
185+
/**
186+
* Returns the initial value for this thread-local variable.
187+
*/
188+
protected V initialValue() throws Exception {
189+
return null;
190+
}
191+
192+
/**
193+
* Invoked when this thread local variable is removed by {@link #remove()}.
194+
*/
195+
protected void onRemoval(@SuppressWarnings("unused") V value) throws Exception {
196+
}
197+
}

0 commit comments

Comments
 (0)