You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2019/12/16 16:12:22 UTC

[skywalking] branch master updated: [Feature] Add Java agent plugin for Jdk Threading classes (#4067)

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new 3f48790  [Feature] Add Java agent plugin for Jdk Threading classes (#4067)
3f48790 is described below

commit 3f48790c36b6887fe849a1fc9a419debbf5c6782
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Tue Dec 17 00:12:14 2019 +0800

    [Feature] Add Java agent plugin for Jdk Threading classes (#4067)
    
    * Add Java agent plugin for Jdk Threading
    
    * Fix expected data according to changes in master
    
    * Update agent.config
    
    * Fix failed plugin test
---
 .github/workflows/plugins-test.yaml                |   4 +-
 .../network/trace/component/ComponentsDefine.java  |   2 +
 .../skywalking/apm/agent/core/conf/Config.java     |  11 ++
 .../agent/core/plugin/match/HierarchyMatch.java    |   3 +-
 .../apm/agent/core/plugin/match/PrefixMatch.java   |  70 ++++++++++++
 .../core/plugin/match/logical/LogicalAndMatch.java |  68 ++++++++++++
 .../match/logical/LogicalMatchOperation.java       |  36 ++++++
 .../core/plugin/match/logical/LogicalOrMatch.java  |  68 ++++++++++++
 .../bootstrap-plugins/jdk-threading-plugin/pom.xml |  46 ++++++++
 .../apm/plugin/jdk/threading/ThreadingConfig.java  |  64 +++++++++++
 .../threading/ThreadingConstructorInterceptor.java |  37 +++++++
 .../jdk/threading/ThreadingMethodInterceptor.java  |  88 +++++++++++++++
 .../threading/define/CallableInstrumentation.java  | 106 ++++++++++++++++++
 .../threading/define/RunnableInstrumentation.java  | 106 ++++++++++++++++++
 .../src/main/resources/skywalking-plugin.def       |  18 +++
 apm-sniffer/bootstrap-plugins/pom.xml              |   1 +
 apm-sniffer/config/agent.config                    |   8 +-
 docs/en/setup/service-agent/java-agent/README.md   |   2 +
 .../src/main/resources/component-libraries.yml     |   3 +
 .../jdk-threading-scenario/bin/startup.sh          |  21 ++++
 .../config/expectedData.yaml                       | 121 +++++++++++++++++++++
 .../jdk-threading-scenario/configuration.yml       |  23 ++++
 .../scenarios/jdk-threading-scenario/pom.xml       |  88 +++++++++++++++
 .../src/main/assembly/assembly.xml                 |  41 +++++++
 .../apm/testcase/jdk/threading/Application.java    |  84 ++++++++++++++
 .../src/main/resources/application.yaml            |  19 ++++
 .../jdk-threading-scenario/support-version.list    |  17 +++
 27 files changed, 1149 insertions(+), 6 deletions(-)

diff --git a/.github/workflows/plugins-test.yaml b/.github/workflows/plugins-test.yaml
index 15b9844..9cb28d5 100644
--- a/.github/workflows/plugins-test.yaml
+++ b/.github/workflows/plugins-test.yaml
@@ -446,7 +446,7 @@ jobs:
       - name: Run elasticsearch-6.x-scenario 6.7.1-6.8.4 (7)
         run: bash test/plugin/run.sh elasticsearch-6.x-scenario
 
-  Oracle_Kafka_JdkHttp:
+  Oracle_Kafka_JdkHttp_JdkThreading:
     runs-on: ubuntu-18.04
     timeout-minutes: 90
     strategy:
@@ -477,6 +477,8 @@ jobs:
         run: bash test/plugin/run.sh kafka-scenario
       - name: Run jdk http (1)
         run: bash test/plugin/run.sh jdk-http-scenario
+      - name: Run jdk threading (1)
+        run: bash test/plugin/run.sh jdk-threading-scenario
 
   MySQL:
     runs-on: ubuntu-18.04
diff --git a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
index 8ac1799..1ec2dec 100755
--- a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
+++ b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
@@ -149,4 +149,6 @@ public class ComponentsDefine {
     public static final OfficialComponent SPRING_TX = new OfficialComponent(78, "spring-tx");
 
     public static final OfficialComponent ARMERIA = new OfficialComponent(79, "Armeria");
+
+    public static final OfficialComponent JDK_THREADING = new OfficialComponent(80, "JdkThreading");
 }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
index 2bc276c..0b0842c 100755
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Config.java
@@ -342,5 +342,16 @@ public class Config {
              */
             public static boolean SIMPLIFY_TRANSACTION_DEFINITION_NAME = false;
         }
+
+        public static class JdkThreading {
+
+            /**
+             * Threading classes ({@link java.lang.Runnable} and {@link java.util.concurrent.Callable}
+             * and their subclasses, including anonymous inner classes)
+             * whose name matches any one of the {@code THREADING_CLASS_PREFIXES} (splitted by ,)
+             * will be instrumented
+             */
+            public static String THREADING_CLASS_PREFIXES = "";
+        }
     }
 }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/HierarchyMatch.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/HierarchyMatch.java
index f134d38..314c4b3 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/HierarchyMatch.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/HierarchyMatch.java
@@ -22,6 +22,7 @@ package org.apache.skywalking.apm.agent.core.plugin.match;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+
 import net.bytebuddy.description.type.TypeDescription;
 import net.bytebuddy.description.type.TypeList;
 import net.bytebuddy.matcher.ElementMatcher;
@@ -101,7 +102,7 @@ public class HierarchyMatch implements IndirectMatch {
 
     }
 
-    public static ClassMatch byHierarchyMatch(String[] parentTypes) {
+    public static IndirectMatch byHierarchyMatch(String... parentTypes) {
         return new HierarchyMatch(parentTypes);
     }
 }
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/PrefixMatch.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/PrefixMatch.java
new file mode 100644
index 0000000..d2cb78f
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/PrefixMatch.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+package org.apache.skywalking.apm.agent.core.plugin.match;
+
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.matcher.ElementMatchers;
+
+/**
+ * Match classes by any one of the given {@link #prefixes}
+ *
+ * @author kezhenxu94
+ */
+@SuppressWarnings("rawtypes")
+public class PrefixMatch implements IndirectMatch {
+    private String[] prefixes;
+
+    private PrefixMatch(String... prefixes) {
+        if (prefixes == null || prefixes.length == 0) {
+            throw new IllegalArgumentException("prefixes argument is null or empty");
+        }
+        this.prefixes = prefixes;
+    }
+
+    @Override
+    public ElementMatcher.Junction buildJunction() {
+        ElementMatcher.Junction junction = null;
+
+        for (String prefix : prefixes) {
+            if (junction == null) {
+                junction = ElementMatchers.nameStartsWith(prefix);
+            } else {
+                junction = junction.and(ElementMatchers.nameStartsWith(prefix));
+            }
+        }
+
+        return junction;
+    }
+
+    @Override
+    public boolean isMatch(TypeDescription typeDescription) {
+        for (final String prefix : prefixes) {
+            if (typeDescription.getName().startsWith(prefix)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static PrefixMatch nameStartsWith(final String... prefixes) {
+        return new PrefixMatch(prefixes);
+    }
+}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalAndMatch.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalAndMatch.java
new file mode 100644
index 0000000..dc523ae
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalAndMatch.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.agent.core.plugin.match.logical;
+
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+
+/**
+ * Match classes by multiple criteria with AND conjunction
+ *
+ * @author kezhenxu94
+ */
+public class LogicalAndMatch implements IndirectMatch {
+    private final IndirectMatch[] indirectMatches;
+
+    /**
+     * Don't instantiate this class directly, use {@link LogicalMatchOperation} instead
+     *
+     * @param indirectMatches the matching criteria to conjunct with AND
+     */
+    LogicalAndMatch(final IndirectMatch... indirectMatches) {
+        this.indirectMatches = indirectMatches;
+    }
+
+    @Override
+    public ElementMatcher.Junction buildJunction() {
+        ElementMatcher.Junction junction = null;
+
+        for (final IndirectMatch indirectMatch : indirectMatches) {
+            if (junction == null) {
+                junction = indirectMatch.buildJunction();
+            } else {
+                junction = junction.and(indirectMatch.buildJunction());
+            }
+        }
+
+        return junction;
+    }
+
+    @Override
+    public boolean isMatch(final TypeDescription typeDescription) {
+        for (final IndirectMatch indirectMatch : indirectMatches) {
+            if (!indirectMatch.isMatch(typeDescription)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalMatchOperation.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalMatchOperation.java
new file mode 100644
index 0000000..0fa5b83
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalMatchOperation.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.agent.core.plugin.match.logical;
+
+import org.apache.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+
+/**
+ * Util class to help to construct logical operations on {@link org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch}s
+ *
+ * @author kezhenxu94
+ */
+public class LogicalMatchOperation {
+    public static IndirectMatch and(final IndirectMatch... matches) {
+        return new LogicalAndMatch(matches);
+    }
+
+    public static IndirectMatch or(final IndirectMatch... matches) {
+        return new LogicalOrMatch(matches);
+    }
+}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalOrMatch.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalOrMatch.java
new file mode 100644
index 0000000..1a10a4f
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/match/logical/LogicalOrMatch.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.agent.core.plugin.match.logical;
+
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+
+/**
+ * Match classes by multiple criteria with OR conjunction
+ *
+ * @author kezhenxu94
+ */
+public class LogicalOrMatch implements IndirectMatch {
+    private final IndirectMatch[] indirectMatches;
+
+    /**
+     * Don't instantiate this class directly, use {@link LogicalMatchOperation} instead
+     *
+     * @param indirectMatches the matching criteria to conjunct with OR
+     */
+    LogicalOrMatch(final IndirectMatch... indirectMatches) {
+        this.indirectMatches = indirectMatches;
+    }
+
+    @Override
+    public ElementMatcher.Junction buildJunction() {
+        ElementMatcher.Junction junction = null;
+
+        for (final IndirectMatch indirectMatch : indirectMatches) {
+            if (junction == null) {
+                junction = indirectMatch.buildJunction();
+            } else {
+                junction = junction.or(indirectMatch.buildJunction());
+            }
+        }
+
+        return junction;
+    }
+
+    @Override
+    public boolean isMatch(final TypeDescription typeDescription) {
+        for (final IndirectMatch indirectMatch : indirectMatches) {
+            if (indirectMatch.isMatch(typeDescription)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/pom.xml b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/pom.xml
new file mode 100755
index 0000000..b9d271a
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/pom.xml
@@ -0,0 +1,46 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.apache.skywalking</groupId>
+        <artifactId>bootstrap-plugins</artifactId>
+        <version>6.6.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>apm-jdk-threading-plugin</artifactId>
+    <packaging>jar</packaging>
+
+    <name>apm-jdk-threading-plugin</name>
+    <description>SkyWalking Java Agent Plugin for JDK threading classes, (Runnable, Callable)</description>
+    <url>https://github.com/apache/skywalking</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-deploy-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingConfig.java b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingConfig.java
new file mode 100644
index 0000000..97145a6
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingConfig.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdk.threading;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.skywalking.apm.agent.core.conf.Config;
+import org.apache.skywalking.apm.agent.core.logging.api.ILog;
+import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
+import org.apache.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
+import org.apache.skywalking.apm.agent.core.plugin.match.PrefixMatch;
+
+import static org.apache.skywalking.apm.agent.core.plugin.match.PrefixMatch.nameStartsWith;
+
+/**
+ * @author kezhenxu94
+ */
+public class ThreadingConfig {
+    private static final ILog LOGGER = LogManager.getLogger(ThreadingConfig.class);
+
+    public static IndirectMatch prefixesMatchesForJdkThreading() {
+        final String jointPrefixes = Config.Plugin.JdkThreading.THREADING_CLASS_PREFIXES;
+
+        if (jointPrefixes == null || jointPrefixes.trim().isEmpty()) {
+            return null;
+        }
+
+        final String[] prefixes = jointPrefixes.split(",");
+
+        final List<PrefixMatch> prefixMatches = new ArrayList<PrefixMatch>();
+
+        for (final String prefix : prefixes) {
+            if (prefix.startsWith("java.") || prefix.startsWith("javax.")) {
+                LOGGER.warn("prefix {} is ignored", prefix);
+                continue;
+            }
+            prefixMatches.add(nameStartsWith(prefix));
+        }
+
+        if (prefixMatches.size() == 0) {
+            return null;
+        }
+
+        return LogicalMatchOperation.or(prefixMatches.toArray(new PrefixMatch[0]));
+    }
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingConstructorInterceptor.java b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingConstructorInterceptor.java
new file mode 100644
index 0000000..3ca000e
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingConstructorInterceptor.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdk.threading;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+
+/**
+ * @author kezhenxu94
+ */
+public class ThreadingConstructorInterceptor implements InstanceConstructorInterceptor {
+
+    @Override
+    public void onConstruct(final EnhancedInstance objInst, final Object[] allArguments) {
+        if (ContextManager.isActive()) {
+            objInst.setSkyWalkingDynamicField(ContextManager.capture());
+        }
+    }
+
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingMethodInterceptor.java b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingMethodInterceptor.java
new file mode 100644
index 0000000..c1607da
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/ThreadingMethodInterceptor.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdk.threading;
+
+import java.lang.reflect.Method;
+
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+/**
+ * @author kezhenxu94
+ */
+public class ThreadingMethodInterceptor implements InstanceMethodsAroundInterceptor {
+
+    @Override
+    public void beforeMethod(
+        final EnhancedInstance objInst,
+        final Method method,
+        final Object[] allArguments,
+        final Class<?>[] argumentsTypes,
+        final MethodInterceptResult result) {
+
+        AbstractSpan span = ContextManager.createLocalSpan(generateOperationName(objInst, method));
+        span.setComponent(ComponentsDefine.JDK_THREADING);
+
+        final Object storedField = objInst.getSkyWalkingDynamicField();
+        if (storedField != null) {
+            final ContextSnapshot contextSnapshot = (ContextSnapshot) storedField;
+            ContextManager.continued(contextSnapshot);
+        }
+
+    }
+
+    @Override
+    public Object afterMethod(
+        final EnhancedInstance objInst,
+        final Method method,
+        final Object[] allArguments,
+        final Class<?>[] argumentsTypes,
+        final Object ret) {
+
+        final Object storedField = objInst.getSkyWalkingDynamicField();
+        if (storedField != null) {
+            ContextManager.stopSpan();
+        }
+
+        return ret;
+    }
+
+    @Override
+    public void handleMethodException(
+        final EnhancedInstance objInst,
+        final Method method,
+        final Object[] allArguments,
+        final Class<?>[] argumentsTypes,
+        final Throwable t) {
+
+        if (ContextManager.isActive()) {
+            ContextManager.activeSpan().errorOccurred().log(t);
+        }
+    }
+
+    private String generateOperationName(final EnhancedInstance objInst, final Method method) {
+        return "Threading/" + objInst.getClass().getName() + "/" + method.getName();
+    }
+
+}
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/define/CallableInstrumentation.java b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/define/CallableInstrumentation.java
new file mode 100644
index 0000000..a32560e
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/define/CallableInstrumentation.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdk.threading.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
+import org.apache.skywalking.apm.plugin.jdk.threading.ThreadingConfig;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch.byHierarchyMatch;
+
+/**
+ * @author kezhenxu94
+ */
+public class CallableInstrumentation extends ClassEnhancePluginDefine {
+    private static final String CALLABLE_CLASS = "java.util.concurrent.Callable";
+    private static final String CALLABLE_CLASS_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdk.threading.ThreadingConstructorInterceptor";
+
+    private static final String CALLABLE_CALL_METHOD = "call";
+    private static final String CALLABLE_CALL_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdk.threading.ThreadingMethodInterceptor";
+
+    @Override
+    protected ClassMatch enhanceClass() {
+        final IndirectMatch prefixMatches = ThreadingConfig.prefixesMatchesForJdkThreading();
+
+        if (prefixMatches == null) {
+            return null;
+        }
+
+        return LogicalMatchOperation.and(prefixMatches, byHierarchyMatch(CALLABLE_CLASS));
+    }
+
+    @Override
+    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+        return new ConstructorInterceptPoint[]{
+            new ConstructorInterceptPoint() {
+                @Override
+                public ElementMatcher<MethodDescription> getConstructorMatcher() {
+                    return any();
+                }
+
+                @Override
+                public String getConstructorInterceptor() {
+                    return CALLABLE_CLASS_INTERCEPTOR;
+                }
+            }
+        };
+    }
+
+    @Override
+    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+        return new InstanceMethodsInterceptPoint[]{
+            new InstanceMethodsInterceptPoint() {
+                @Override
+                public ElementMatcher<MethodDescription> getMethodsMatcher() {
+                    return named(CALLABLE_CALL_METHOD).and(takesArguments(0));
+                }
+
+                @Override
+                public String getMethodsInterceptor() {
+                    return CALLABLE_CALL_METHOD_INTERCEPTOR;
+                }
+
+                @Override
+                public boolean isOverrideArgs() {
+                    return false;
+                }
+            }
+        };
+    }
+
+    @Override
+    public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
+        return new StaticMethodsInterceptPoint[0];
+    }
+
+    @Override
+    public boolean isBootstrapInstrumentation() {
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/define/RunnableInstrumentation.java b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/define/RunnableInstrumentation.java
new file mode 100644
index 0000000..c77e256
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdk/threading/define/RunnableInstrumentation.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.jdk.threading.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.logical.LogicalMatchOperation;
+import org.apache.skywalking.apm.plugin.jdk.threading.ThreadingConfig;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static org.apache.skywalking.apm.agent.core.plugin.match.HierarchyMatch.byHierarchyMatch;
+
+/**
+ * @author kezhenxu94
+ */
+public class RunnableInstrumentation extends ClassEnhancePluginDefine {
+    private static final String RUNNABLE_CLASS = "java.lang.Runnable";
+    private static final String RUNNABLE_CLASS_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdk.threading.ThreadingConstructorInterceptor";
+
+    private static final String RUNNABLE_RUN_METHOD = "run";
+    private static final String RUNNABLE_RUN_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdk.threading.ThreadingMethodInterceptor";
+
+    @Override
+    protected ClassMatch enhanceClass() {
+        final IndirectMatch prefixMatches = ThreadingConfig.prefixesMatchesForJdkThreading();
+
+        if (prefixMatches == null) {
+            return null;
+        }
+
+        return LogicalMatchOperation.and(prefixMatches, byHierarchyMatch(RUNNABLE_CLASS));
+    }
+
+    @Override
+    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+        return new ConstructorInterceptPoint[]{
+            new ConstructorInterceptPoint() {
+                @Override
+                public ElementMatcher<MethodDescription> getConstructorMatcher() {
+                    return any();
+                }
+
+                @Override
+                public String getConstructorInterceptor() {
+                    return RUNNABLE_CLASS_INTERCEPTOR;
+                }
+            }
+        };
+    }
+
+    @Override
+    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+        return new InstanceMethodsInterceptPoint[]{
+            new InstanceMethodsInterceptPoint() {
+                @Override
+                public ElementMatcher<MethodDescription> getMethodsMatcher() {
+                    return named(RUNNABLE_RUN_METHOD).and(takesArguments(0));
+                }
+
+                @Override
+                public String getMethodsInterceptor() {
+                    return RUNNABLE_RUN_METHOD_INTERCEPTOR;
+                }
+
+                @Override
+                public boolean isOverrideArgs() {
+                    return false;
+                }
+            }
+        };
+    }
+
+    @Override
+    public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
+        return new StaticMethodsInterceptPoint[0];
+    }
+
+    @Override
+    public boolean isBootstrapInstrumentation() {
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000..06aaee3
--- /dev/null
+++ b/apm-sniffer/bootstrap-plugins/jdk-threading-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+jdk-threading-plugin=org.apache.skywalking.apm.plugin.jdk.threading.define.RunnableInstrumentation
+jdk-threading-plugin=org.apache.skywalking.apm.plugin.jdk.threading.define.CallableInstrumentation
\ No newline at end of file
diff --git a/apm-sniffer/bootstrap-plugins/pom.xml b/apm-sniffer/bootstrap-plugins/pom.xml
index b421ee1..eef4583 100644
--- a/apm-sniffer/bootstrap-plugins/pom.xml
+++ b/apm-sniffer/bootstrap-plugins/pom.xml
@@ -42,6 +42,7 @@
 
     <modules>
         <module>jdk-http-plugin</module>
+        <module>jdk-threading-plugin</module>
     </modules>
 
     <dependencies>
diff --git a/apm-sniffer/config/agent.config b/apm-sniffer/config/agent.config
index 6e03ff2..dfa6aee 100644
--- a/apm-sniffer/config/agent.config
+++ b/apm-sniffer/config/agent.config
@@ -28,14 +28,14 @@ agent.service_name=${SW_AGENT_NAME:Your_ApplicationName}
 # agent.authentication = ${SW_AGENT_AUTHENTICATION:xxxx}
 
 # The max amount of spans in a single segment.
-# Through this config item, skywalking keep your application memory cost estimated.
+# Through this config item, SkyWalking keep your application memory cost estimated.
 # agent.span_limit_per_segment=${SW_AGENT_SPAN_LIMIT:300}
 
 # Ignore the segments if their operation names end with these suffix.
 # agent.ignore_suffix=${SW_AGENT_IGNORE_SUFFIX:.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg}
 
-# If true, skywalking agent will save all instrumented classes files in `/debugging` folder.
-# Skywalking team may ask for these files in order to resolve compatible problem.
+# If true, SkyWalking agent will save all instrumented classes files in `/debugging` folder.
+# SkyWalking team may ask for these files in order to resolve compatible problem.
 # agent.is_open_debugging_class = ${SW_AGENT_OPEN_DEBUG:true}
 
 # The operationName max length
@@ -61,4 +61,4 @@ logging.level=${SW_LOGGING_LEVEL:DEBUG}
 # logging.max_history_files=${SW_LOGGING_MAX_HISTORY_FILES:-1}
 
 # mysql plugin configuration
-# plugin.mysql.trace_sql_parameters=${SW_MYSQL_TRACE_SQL_PARAMETERS:false}
\ No newline at end of file
+# plugin.mysql.trace_sql_parameters=${SW_MYSQL_TRACE_SQL_PARAMETERS:false}
diff --git a/docs/en/setup/service-agent/java-agent/README.md b/docs/en/setup/service-agent/java-agent/README.md
index 787d90e..c316651 100755
--- a/docs/en/setup/service-agent/java-agent/README.md
+++ b/docs/en/setup/service-agent/java-agent/README.md
@@ -117,6 +117,7 @@ property key | Description | Default |
 `plugin.light4j.trace_handler_chain`|If true, trace all middleware/business handlers that are part of the Light4J handler chain for a request.|false|
 `plugin.opgroup.*`|Support operation name customize group rules in different plugins. Read [Group rule supported plugins](op_name_group_rule.md)|Not set|
 `plugin.springtransaction.simplify_transaction_definition_name`|If true, the transaction definition name will be simplified.|false|
+`plugin.jdkthreading.threading_class_prefixes` | Threading classes (`java.lang.Runnable` and `java.util.concurrent.Callable`) and their subclasses, including anonymous inner classes whose name match any one of the `THREADING_CLASS_PREFIXES` (splitted by `,`) will be instrumented, make sure to only specify as narrow prefixes as what you're expecting to instrument, (`java.` and `javax.` will be ignored due to safety issues) | Not set |
 
 ## Optional Plugins
 Java agent plugins are all pluggable. Optional plugins could be provided in `optional-plugins` folder under agent or 3rd party repositories.
@@ -140,6 +141,7 @@ For using these plugins, you need to put the target plugin jar file into `/plugi
 
 Now, we have the following known bootstrap plugins.
 * Plugin of JDK HttpURLConnection. Agent is compatible with JDK 1.6+
+* Plugin of JDK Callable and Runnable. Agent is compatible with JDK 1.6+
 
 ## Advanced Features
 * Set the settings through system properties for config file override. Read [setting override](Setting-override.md).
diff --git a/oap-server/server-bootstrap/src/main/resources/component-libraries.yml b/oap-server/server-bootstrap/src/main/resources/component-libraries.yml
index 90e1d65..bac1b0c 100755
--- a/oap-server/server-bootstrap/src/main/resources/component-libraries.yml
+++ b/oap-server/server-bootstrap/src/main/resources/component-libraries.yml
@@ -266,6 +266,9 @@ spring-tx:
 Armeria:
   id: 79
   languages: Java
+JdkThreading:
+  id: 80
+  languages: Java
 
 # .NET/.NET Core components
 # [3000, 4000) for C#/.NET only
diff --git a/test/plugin/scenarios/jdk-threading-scenario/bin/startup.sh b/test/plugin/scenarios/jdk-threading-scenario/bin/startup.sh
new file mode 100644
index 0000000..98bfae7
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/bin/startup.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+home="$(cd "$(dirname $0)"; pwd)"
+
+java -Dskywalking.plugin.jdkthreading.threading_class_prefixes=test.org.apache.skywalking. -jar ${agent_opts} ${home}/../libs/jdk-threading-scenario.jar &
\ No newline at end of file
diff --git a/test/plugin/scenarios/jdk-threading-scenario/config/expectedData.yaml b/test/plugin/scenarios/jdk-threading-scenario/config/expectedData.yaml
new file mode 100644
index 0000000..c4c492d
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/config/expectedData.yaml
@@ -0,0 +1,121 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+registryItems:
+  applications:
+    - {jdk-threading-scenario: 2}
+  instances:
+    - {jdk-threading-scenario: 1}
+  operationNames:
+    - jdk-threading-scenario: ['/greet/{username}']
+  heartbeat: []
+
+segmentItems:
+  - applicationCode: jdk-threading-scenario
+    segmentSize: ge 4
+    segments:
+      - segmentId: not null
+        spans:
+          - operationName: /greet/{username}
+            operationId: 0
+            parentSpanId: -1
+            spanId: 0
+            spanLayer: Http
+            startTime: nq 0
+            endTime: nq 0
+            componentId: 14
+            componentName: ''
+            isError: false
+            spanType: Entry
+            peer: ''
+            peerId: 0
+            tags:
+              - {key: url, value: 'http://localhost:8080/greet/skywalking'}
+              - {key: http.method, value: GET}
+
+      - segmentId: not null
+        spans:
+          - operationName: /apache/skywalking
+            operationId: 0
+            parentSpanId: 0
+            spanId: 1
+            spanLayer: Http
+            startTime: nq 0
+            endTime: nq 0
+            componentId: 13
+            componentName: ''
+            isError: false
+            spanType: Exit
+            peer: github.com:443
+            peerId: 0
+            tags:
+              - {key: url, value: 'https://github.com:-1/apache/skywalking'}
+              - {key: http.method, value: GET}
+          - operationName: Threading/test.org.apache.skywalking.apm.testcase.jdk.threading.Application$TestController$1/run
+            operationId: 0
+            parentSpanId: -1
+            spanId: 0
+            spanLayer: Unknown
+            startTime: nq 0
+            endTime: nq 0
+            componentId: 80
+            componentName: ''
+            isError: false
+            spanType: Local
+            peer: ''
+            peerId: 0
+            refs:
+              - {parentEndpointId: 0, parentEndpoint: '/greet/{username}', networkAddressId: 0,
+                 entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, parentTraceSegmentId: not null,
+                 parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: '/greet/{username}',
+                 entryServiceInstanceId: 1}
+
+      - segmentId: not null
+        spans:
+          - operationName: /apache/skywalking
+            operationId: 0
+            parentSpanId: 0
+            spanId: 1
+            spanLayer: Http
+            startTime: nq 0
+            endTime: nq 0
+            componentId: 13
+            componentName: ''
+            isError: false
+            spanType: Exit
+            peer: github.com:443
+            peerId: 0
+            tags:
+              - {key: url, value: 'https://github.com:-1/apache/skywalking'}
+              - {key: http.method, value: GET}
+          - operationName: Threading/test.org.apache.skywalking.apm.testcase.jdk.threading.Application$TestController$2/call
+            operationId: 0
+            parentSpanId: -1
+            spanId: 0
+            spanLayer: Unknown
+            startTime: nq 0
+            endTime: nq 0
+            componentId: 80
+            componentName: ''
+            isError: false
+            spanType: Local
+            peer: ''
+            peerId: 0
+            refs:
+              - {parentEndpointId: 0, parentEndpoint: '/greet/{username}', networkAddressId: 0,
+                 entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, parentTraceSegmentId: not null,
+                 parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: '/greet/{username}',
+                 entryServiceInstanceId: 1}
\ No newline at end of file
diff --git a/test/plugin/scenarios/jdk-threading-scenario/configuration.yml b/test/plugin/scenarios/jdk-threading-scenario/configuration.yml
new file mode 100644
index 0000000..b129cc2
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/configuration.yml
@@ -0,0 +1,23 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+type: jvm
+entryService: http://localhost:8080/greet/skywalking
+healthCheck: http://localhost:8080/healthCheck
+runningMode: with_bootstrap
+withPlugins: apm-jdk-threading-plugin-*.jar
+startScript: ./bin/startup.sh
+framework: jdk-threading-scenario
diff --git a/test/plugin/scenarios/jdk-threading-scenario/pom.xml b/test/plugin/scenarios/jdk-threading-scenario/pom.xml
new file mode 100644
index 0000000..42b68ac
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/pom.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.apache.skywalking</groupId>
+    <artifactId>jdk-threading-scenario</artifactId>
+    <version>5.0.0</version>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <compiler.version>1.6</compiler.version>
+        <spring.boot.version>2.1.6.RELEASE</spring.boot.version>
+    </properties>
+
+    <name>skywalking-jdk-threading-scenario</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>${spring.boot.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>jdk-threading-scenario</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${spring.boot.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.1</version>
+                <configuration>
+                    <source>${compiler.version}</source>
+                    <target>${compiler.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>assemble</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/main/assembly/assembly.xml</descriptor>
+                            </descriptors>
+                            <outputDirectory>./target/</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/test/plugin/scenarios/jdk-threading-scenario/src/main/assembly/assembly.xml b/test/plugin/scenarios/jdk-threading-scenario/src/main/assembly/assembly.xml
new file mode 100644
index 0000000..a733286
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/src/main/assembly/assembly.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+<assembly
+        xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+    <formats>
+        <format>zip</format>
+    </formats>
+
+    <fileSets>
+        <fileSet>
+            <directory>./bin</directory>
+            <fileMode>0775</fileMode>
+        </fileSet>
+    </fileSets>
+
+    <files>
+        <file>
+            <source>./target/jdk-threading-scenario.jar</source>
+            <outputDirectory>./libs</outputDirectory>
+            <fileMode>0775</fileMode>
+        </file>
+    </files>
+</assembly>
\ No newline at end of file
diff --git a/test/plugin/scenarios/jdk-threading-scenario/src/main/java/test/org/apache/skywalking/apm/testcase/jdk/threading/Application.java b/test/plugin/scenarios/jdk-threading-scenario/src/main/java/test/org/apache/skywalking/apm/testcase/jdk/threading/Application.java
new file mode 100644
index 0000000..1cbdedb
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/src/main/java/test/org/apache/skywalking/apm/testcase/jdk/threading/Application.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package test.org.apache.skywalking.apm.testcase.jdk.threading;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author kezhenxu94
+ */
+@SpringBootApplication
+public class Application {
+
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+    }
+
+    @Bean
+    public RestTemplate restTemplate() {
+        return new RestTemplate();
+    }
+
+    @RestController
+    static class TestController {
+        private final RestTemplate restTemplate;
+        private final ExecutorService executorService;
+
+        public TestController(final RestTemplate restTemplate) {
+            this.restTemplate = restTemplate;
+            this.executorService = Executors.newSingleThreadScheduledExecutor();
+        }
+
+        @GetMapping("/healthCheck")
+        public String healthCheck() {
+            return "Success";
+        }
+
+        @GetMapping("/greet/{username}")
+        public String testCase(@PathVariable final String username) throws ExecutionException, InterruptedException {
+            Runnable runnable = new Runnable() {
+                @Override
+                public void run() {
+                    restTemplate.getForEntity("https://github.com/apache/skywalking", String.class);
+                }
+            };
+
+            executorService.execute(runnable);
+
+            executorService.submit(new Callable<String>() {
+                @Override
+                public String call() {
+                    return restTemplate.getForEntity("https://github.com/apache/skywalking", String.class).getBody();
+                }
+            }).get();
+
+            return username;
+        }
+    }
+}
diff --git a/test/plugin/scenarios/jdk-threading-scenario/src/main/resources/application.yaml b/test/plugin/scenarios/jdk-threading-scenario/src/main/resources/application.yaml
new file mode 100644
index 0000000..6ff39eb8
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/src/main/resources/application.yaml
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+server:
+  port: 8080
+
diff --git a/test/plugin/scenarios/jdk-threading-scenario/support-version.list b/test/plugin/scenarios/jdk-threading-scenario/support-version.list
new file mode 100644
index 0000000..feef03c
--- /dev/null
+++ b/test/plugin/scenarios/jdk-threading-scenario/support-version.list
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+all
\ No newline at end of file