我正在使用执行程序通道进行并行调用。
<task:executor id="taskExecutor" pool-size="5"/>
<int:channel id="executorChannel">
<int:dispatcher task-executor="taskExecutor"/>
</int:channel>
我使用的是InheritableThreadLocal变量,由于池大小声明为5,因此在第6次调用后会重置为初始值。
换句话说,1-10中的线程本地值读取为1-5并再次读取1-5。 除ThreadLocal变量问题外,一切正常。
请告知修复。
以下是示例类: 1. HeaderContext - 存储InheritableThreadLocal变量
public final class HeaderContext {
private HeaderContext() {}
private static final InheritableThreadLocal<String> GID = new InheritableThreadLocal<String>() {
@Override
protected String initialValue() {
return new String();
}
};
public static void clear() {
GID.remove();
}
public static void setGID(String gid) {
GID.set(gid);
}
public static String getGID() {
return GID.get();
}
}
2。 TestGateway
@Component
public interface TestGateway {
String testMethod(String name);
}
3。 TestActivator
@Component
public class TestActivator {
public String testMethod(String name){
System.out.println("GID from Inheritable thread local ->"+HeaderContext.getGID());
return name;
}
}
4。测试类
@ContextConfiguration(locations = { "classpath:exec-channel-si.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
public class ThreadLocalGatewayTest {
@Autowired
TestGateway testGateway;
@Test
public void testBrokerageGateway() throws InterruptedException {
for(int i=1;i<=5;i++){
try {
HeaderContext.setGID("gid"+i);
System.out.println("done->" + testGateway.testMethod("name"+i));
} finally {
HeaderContext.clear();
}
Thread.sleep(2000);
}
}
}
5。 SI背景
<task:executor id="taskExecutor" pool-size="2"/>
<context:component-scan base-package="sample.test"/>
<int:channel id="executorChannel">
<int:dispatcher task-executor="taskExecutor"/>
</int:channel>
<int:gateway id="testGateway"
service-interface="sample.test.TestGateway"
default-request-channel="executorChannel">
</int:gateway>
<int:service-activator input-channel="executorChannel" ref="testActivator"/>
输出
GID from Inheritable thread local ->gid1
output->name1
GID from Inheritable thread local ->gid2
output->name2
GID from Inheritable thread local ->gid1
output->name3
GID from Inheritable thread local ->gid2
output->name4
GID from Inheritable thread local ->gid1
output->name5
答案 0 :(得分:1)
嗯,我确定当您在服务中打印ThreadId
时,您会因为您的目的而重复使用线程而感到惊讶:
name-> name1 in the inheritable thread local -> gid1 for thread: pool-1-thread-1
name-> name2 in the inheritable thread local -> gid2 for thread: pool-1-thread-2
name-> name3 in the inheritable thread local -> gid3 for thread: pool-1-thread-3
name-> name4 in the inheritable thread local -> gid4 for thread: pool-1-thread-4
name-> name5 in the inheritable thread local -> gid5 for thread: pool-1-thread-5
name-> name6 in the inheritable thread local -> gid4 for thread: pool-1-thread-4
name-> name10 in the inheritable thread local -> gid1 for thread: pool-1-thread-1
name-> name8 in the inheritable thread local -> gid2 for thread: pool-1-thread-2
name-> name9 in the inheritable thread local -> gid3 for thread: pool-1-thread-3
name-> name7 in the inheritable thread local -> gid5 for thread: pool-1-thread-5
这是简单测试的结果:
private static final ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
@Test
public void testInheritableThreadLocal() throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
final CountDownLatch stopLatch = new CountDownLatch(10);
for (int i = 1; i <= 10; i++) {
final int j = i;
try {
threadLocal.set("gid" + i);
executorService.execute(() -> {
System.out.println("name-> " + "name " + j + " in the inheritable thread local -> "
+ threadLocal.get() + " for thread: " + Thread.currentThread().getName());
stopLatch.countDown();
});
}
finally {
threadLocal.remove();
}
}
assertTrue(stopLatch.await(10, TimeUnit.SECONDS));
}
现在让我们来看看ThreadLocal
JavaDocs:
* This class provides thread-local variables. These variables differ from
* their normal counterparts in that each thread that accesses one (via its
* {@code get} or {@code set} method) has its own, independently initialized
* copy of the variable.
因此,每个线程都有自己的变量副本,并在一个线程中更改它们不会影响另一个线程。
主线程中的InheritableThreadLocal
与普通ThreadLocal
一样。只有这样,新生成的孩子Thread
才能获得main
ThreadLocal
的当前副本。这就是我们为每个新线程看到一个新值的原因,但是当重用那个子线程时,就像ThreadPool
一样,我们仍然会看到它自己的旧值。
请阅读更多有关此事的RTFM!
希望明确