2016-05-04 11 views
1

Ich benutze Executor-Kanal für parallele Anrufe.Executor-Kanal - InheritableThreadLocal Problem

<task:executor id="taskExecutor" pool-size="5"/> 
<int:channel id="executorChannel"> 
    <int:dispatcher task-executor="taskExecutor"/> 
</int:channel> 

ich InheritableThreadLocal Variable verwenden, ist es wieder auf den Ausgangswert nach dem 6. Anruf wegen der Pool-Größe deklariert als 5.

Mit anderen Worten, von 1-10 lokalen Wert Thread gelesen als 1-5 und wieder 1-5. Abgesehen von ThreadLocal-Variablenproblem funktioniert alles einwandfrei.

informieren Sie bitte über die Lösung.

Hier ist die Probe Klassen: 1. HeaderContext - InheritableThreadLocal Variable

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 speichern

@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. Testklasse

@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 Kontext

<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"/> 

Ausgabe

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

Wäre toll, wenn Sie etwas Code-Spiel von unserer Seite teilen würden. –

+0

Ich habe den Beitrag mit einem einfachen Beispiel bearbeitet ... Ihre Hilfe wird sehr geschätzt. –

Antwort

1

Nun, ich bin sicher, wenn Sie ThreadId in Ihren Dienst zu drucken, werden Sie nicht überrascht sein, dass Sie Faden wiederverwenden für Ihren Zweck:

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 

Das Ergebnis der einfachen Test:

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)); 
} 

Lassen Sie uns jetzt einen Blick in ThreadLocal JavaDocs nehmen:

* 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. 

Also, jeder Thread hat seine eigene Kopie von Variablen und ihnen in einem Thread ändern doesn keinen anderen Thread beeinflussen.

Die InheritableThreadLocal im Haupt-Thread ist als eine normale ThreadLocal. Nur mit diesem Gewinn, dass ein neu geborenes Kind Thread eine aktuelle Kopie des mainThreadLocal bekommen wird. Deshalb sehen wir für jeden neuen Thread einen neuen Wert, aber wenn wir diesen untergeordneten Thread wiederverwenden, wie im Fall von ThreadPool, sehen wir immer noch seinen eigenen alten Wert.

Bitte lesen Sie mehr RTFM in der Sache!

Hoffe, dass klar