From 9fb584a4ce8da85b56bfc9a4c45b790a5c3aed50 Mon Sep 17 00:00:00 2001
From: xujingfeng <jingfeng.xjf@alibaba-inc.com>
Date: Mon, 17 Dec 2018 14:50:45 +0800
Subject: [PATCH 1/5] add the notice of code style

---
 CONTRIBUTING.md               |  12 +++++++++++-
 codestyle/manage_profiles.png | Bin 0 -> 430 bytes
 2 files changed, 11 insertions(+), 1 deletion(-)
 create mode 100644 codestyle/manage_profiles.png

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index bd7dc2022cd..918127467a0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -63,4 +63,14 @@ Thanks for contributing!
 ### Code style
 
 We provide a template file [dubbo_codestyle_for_idea.xml](https://github.com/apache/incubator-dubbo/tree/master/codestyle/dubbo_codestyle_for_idea.xml) for IntelliJ idea, you can import it to you IDE. 
-If you use Eclipse you can config manually by referencing the same file.
\ No newline at end of file
+If you use Eclipse you can config manually by referencing the same file.
+
+**NOTICE**
+
+It is very important to set the dubbo_codestyle_for_idea.xml, otherwise you will fail to pass the Travis CI. Steps to set the code style are as below:
+
+1. Enter `Editor > Code Style`
+2. To manage a code style scheme, in the Code Style page, select the desired scheme from the drop-down list, and click ![codestyle/manage_profiles.png](manage profiles).
+From the drop-down list, select `Import Scheme`, then select this option `IntelliJ IDEA code style XML` to import scheme
+3. In the Scheme field, type the name of the new scheme and press ⏎ to save the changes.
+
diff --git a/codestyle/manage_profiles.png b/codestyle/manage_profiles.png
new file mode 100644
index 0000000000000000000000000000000000000000..1664d67ea43d2e2b5f38f5dc2e08ae91b195cd3a
GIT binary patch
literal 430
zcmeAS@N?(olHy`uVBq!ia0vp^(m*W90VEinmUA@$Db50q$YKTtz9S&aI8~buq=LP~
z)7O>#A+rd-puic`HP^sGt`Q}Ur6n2pMGPy~o$&w)@st3CTvCgZi!uvJGV}8oggF(J
zf#O^sap(Mk%A(Blj1q=5{Aa9yqI_V{qSQo?QiYPt+*AhB@BExV8BUN)aDG}zd16s2
zLu|o+kaBLY;hDwBIf+1}MGV^yZ0QFIbAW`y6N~aP^U@g(NIz=_im^lVmlh?bGJO5t
z{2HdrIX^cyHLrx>+nH(mfnsbRWg(d*IjIaQ-d$1$id1^KIEHAPzk1P-uf>4JC9v-g
zqo(Xb4uy$kA~M~F9<UX12j^_;5XdU{t&)9APsjeKH}AV#zC{a!o?T(O*Z8^R$`VEf
z{grD?Q+rguPLgoA^PMBXj4}Awwt0EK--o!H_KEtPJyUX_SnU7lOJ3WYi?2Ui`TO$O
deP6!6mWkb)D{mUk;tzBLgQu&X%Q~loCII>1lo<d3

literal 0
HcmV?d00001


From 434bcfe29659d70b07d8e5457123d3f197761491 Mon Sep 17 00:00:00 2001
From: xujingfeng <jingfeng.xjf@alibaba-inc.com>
Date: Mon, 17 Dec 2018 14:53:20 +0800
Subject: [PATCH 2/5] modify the pic

---
 CONTRIBUTING.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 918127467a0..b987b16e658 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -70,7 +70,7 @@ If you use Eclipse you can config manually by referencing the same file.
 It is very important to set the dubbo_codestyle_for_idea.xml, otherwise you will fail to pass the Travis CI. Steps to set the code style are as below:
 
 1. Enter `Editor > Code Style`
-2. To manage a code style scheme, in the Code Style page, select the desired scheme from the drop-down list, and click ![codestyle/manage_profiles.png](manage profiles).
+2. To manage a code style scheme, in the Code Style page, select the desired scheme from the drop-down list, and click ![manage profiles](codestyle/manage_profiles.png).
 From the drop-down list, select `Import Scheme`, then select this option `IntelliJ IDEA code style XML` to import scheme
 3. In the Scheme field, type the name of the new scheme and press ⏎ to save the changes.
 

From 4db2d6fe58e90c7e907070cc19697f5fc45bab45 Mon Sep 17 00:00:00 2001
From: xujingfeng <jingfeng.xjf@alibaba-inc.com>
Date: Mon, 17 Dec 2018 15:34:25 +0800
Subject: [PATCH 3/5] del teh faq.md, move to dubbo admin

---
 FAQ.md | 25 -------------------------
 1 file changed, 25 deletions(-)
 delete mode 100644 FAQ.md

diff --git a/FAQ.md b/FAQ.md
deleted file mode 100644
index 28e2f0cc564..00000000000
--- a/FAQ.md
+++ /dev/null
@@ -1,25 +0,0 @@
-### Where is dubbo-admin?
-
-dubbo-admin has been moved from core repository to https://github.com/apache/incubator-dubbo-ops since 2.6.1
-
-### Which version should I choose?
-
-Currently, dubbo keeps 3 versions evolve in parallel:
-
-* 2.7.x (master): requires Java 1.8, major feature branch.
-
-* 2.6.x: requires Java 1.6, minor feature & bugfix branch, GA, production ready.
-
-* 2.5.x: requires Java 1.6, maintenance branch, only accept security vulnerability and critical bugfix, expected to be EOL soon.
-
-check [this](https://github.com/apache/incubator-dubbo/issues/1208) for detailed version management plan.
-
-For contributors, please make sure all changes on the right branch, that is, most of the pull request should go to 2.7.x, and be backported to 2.6.x and 2.5.x if necessary. If the fix is specific to a branch, please make sure your pull request goes to the right branch.
-
-For committers, make sure select the right label and target branch for every PR, and don't forget to back port the fix to lower version is necessary.
-
-####  How to register ip correctly in docker?  
-
-[Example question](https://github.com/alibaba/dubbo/issues/742)  
-
-Dubbo supports specifying ip/port via system environment variables, examples can be found [here](https://github.com/dubbo/dubbo-samples/tree/master/dubbo-samples-docker).

From 3c26188a282da363348bd1fceeb4dac4a320ea32 Mon Sep 17 00:00:00 2001
From: xujingfeng <jingfeng.xjf@alibaba-inc.com>
Date: Sat, 19 Jan 2019 20:07:41 +0800
Subject: [PATCH 4/5] improve:remove the heartbeat on server side

---
 .../support/header/CloseTimerTask.java        | 55 +++++++++++++++++++
 .../support/header/HeaderExchangeClient.java  | 35 ++++++------
 .../support/header/HeaderExchangeServer.java  | 47 +++++++---------
 .../support/header/ReconnectTimerTask.java    | 33 +++++------
 4 files changed, 107 insertions(+), 63 deletions(-)
 create mode 100644 dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/CloseTimerTask.java

diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/CloseTimerTask.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/CloseTimerTask.java
new file mode 100644
index 00000000000..4081c309d05
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/CloseTimerTask.java
@@ -0,0 +1,55 @@
+/*
+ * 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.dubbo.remoting.exchange.support.header;
+
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.remoting.Channel;
+
+/**
+ * CloseTimerTask
+ */
+public class CloseTimerTask extends AbstractTimerTask {
+
+    private static final Logger logger = LoggerFactory.getLogger(CloseTimerTask.class);
+
+    private final int idleTimeout;
+
+    public CloseTimerTask(ChannelProvider channelProvider, Long heartbeatTimeoutTick, int idleTimeout) {
+        super(channelProvider, heartbeatTimeoutTick);
+        this.idleTimeout = idleTimeout;
+    }
+
+    @Override
+    protected void doTask(Channel channel) {
+        try {
+            Long lastRead = lastRead(channel);
+            Long lastWrite = lastWrite(channel);
+            Long now = now();
+            // check ping & pong at server
+            if ((lastRead != null && now - lastRead > idleTimeout)
+                    || (lastWrite != null && now - lastWrite > idleTimeout)) {
+                logger.warn("Close channel " + channel + ", because idleCheck timeout: "
+                        + idleTimeout + "ms");
+                channel.close();
+            }
+        } catch (Throwable t) {
+            logger.warn("Exception when close remote channel " + channel.getRemoteAddress(), t);
+        }
+    }
+}
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java
index 3abbe5b5422..4c821a99980 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java
@@ -39,11 +39,10 @@ public class HeaderExchangeClient implements ExchangeClient {
 
     private final Client client;
     private final ExchangeChannel channel;
-    // heartbeat(ms), default value is 0 , won't execute a heartbeat.
     private int heartbeat;
-    private int heartbeatTimeout;
+    private int idleTimeout;
 
-    private HashedWheelTimer heartbeatTimer;
+    private HashedWheelTimer idleCheckTimer;
 
     public HeaderExchangeClient(Client client, boolean needHeartbeat) {
         if (client == null) {
@@ -55,16 +54,16 @@ public HeaderExchangeClient(Client client, boolean needHeartbeat) {
 
         this.heartbeat = client.getUrl().getParameter(Constants.HEARTBEAT_KEY, dubbo != null &&
                 dubbo.startsWith("1.0.") ? Constants.DEFAULT_HEARTBEAT : 0);
-        this.heartbeatTimeout = client.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3);
-        if (heartbeatTimeout < heartbeat * 2) {
-            throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2");
+        this.idleTimeout = client.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3);
+        if (idleTimeout < heartbeat * 2) {
+            throw new IllegalStateException("idleTimeout < heartbeatInterval * 2");
         }
 
         if (needHeartbeat) {
             long tickDuration = calculateLeastDuration(heartbeat);
-            heartbeatTimer = new HashedWheelTimer(new NamedThreadFactory("dubbo-client-heartbeat", true), tickDuration,
+            idleCheckTimer = new HashedWheelTimer(new NamedThreadFactory("dubbo-client-idleCheck", true), tickDuration,
                     TimeUnit.MILLISECONDS, Constants.TICKS_PER_WHEEL);
-            startHeartbeatTimer();
+            startIdleCheckTimer();
         }
     }
 
@@ -178,28 +177,28 @@ public boolean hasAttribute(String key) {
         return channel.hasAttribute(key);
     }
 
-    private void startHeartbeatTimer() {
+    private void startIdleCheckTimer() {
         AbstractTimerTask.ChannelProvider cp = () -> Collections.singletonList(HeaderExchangeClient.this);
 
         long heartbeatTick = calculateLeastDuration(heartbeat);
-        long heartbeatTimeoutTick = calculateLeastDuration(heartbeatTimeout);
+        long heartbeatTimeoutTick = calculateLeastDuration(idleTimeout);
         HeartbeatTimerTask heartBeatTimerTask = new HeartbeatTimerTask(cp, heartbeatTick, heartbeat);
-        ReconnectTimerTask reconnectTimerTask = new ReconnectTimerTask(cp, heartbeatTimeoutTick, heartbeatTimeout);
+        ReconnectTimerTask reconnectTimerTask = new ReconnectTimerTask(cp, heartbeatTimeoutTick, idleTimeout);
 
         // init task and start timer.
-        heartbeatTimer.newTimeout(heartBeatTimerTask, heartbeatTick, TimeUnit.MILLISECONDS);
-        heartbeatTimer.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS);
+        idleCheckTimer.newTimeout(heartBeatTimerTask, heartbeatTick, TimeUnit.MILLISECONDS);
+        idleCheckTimer.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS);
     }
 
-    private void stopHeartbeatTimer() {
-        if (heartbeatTimer != null) {
-            heartbeatTimer.stop();
-            heartbeatTimer = null;
+    private void stopIdleCheckTimer() {
+        if (idleCheckTimer != null) {
+            idleCheckTimer.stop();
+            idleCheckTimer = null;
         }
     }
 
     private void doClose() {
-        stopHeartbeatTimer();
+        stopIdleCheckTimer();
     }
 
     /**
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java
index e339c15ab94..13cace0e66e 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java
@@ -48,12 +48,11 @@ public class HeaderExchangeServer implements ExchangeServer {
     protected final Logger logger = LoggerFactory.getLogger(getClass());
 
     private final Server server;
-    // heartbeat timeout (ms), default value is 0 , won't execute a heartbeat.
     private int heartbeat;
-    private int heartbeatTimeout;
+    private int idleTimeout;
     private AtomicBoolean closed = new AtomicBoolean(false);
 
-    private HashedWheelTimer heartbeatTimer;
+    private HashedWheelTimer idleCheckTimer;
 
     public HeaderExchangeServer(Server server) {
         if (server == null) {
@@ -61,12 +60,12 @@ public HeaderExchangeServer(Server server) {
         }
         this.server = server;
         this.heartbeat = server.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0);
-        this.heartbeatTimeout = server.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3);
-        if (heartbeatTimeout < heartbeat * 2) {
-            throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2");
+        this.idleTimeout = server.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3);
+        if (idleTimeout < heartbeat * 2) {
+            throw new IllegalStateException("idleTimeout < heartbeatInterval * 2");
         }
 
-        startHeartbeatTimer();
+        startIdleCheckTimer();
     }
 
     public Server getServer() {
@@ -149,7 +148,7 @@ private void doClose() {
         if (!closed.compareAndSet(false, true)) {
             return;
         }
-        stopHeartbeatTimer();
+        stopIdleCheckTimer();
     }
 
     @Override
@@ -210,14 +209,14 @@ public void reset(URL url) {
                 int h = url.getParameter(Constants.HEARTBEAT_KEY, heartbeat);
                 int t = url.getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, h * 3);
                 if (t < h * 2) {
-                    throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2");
+                    throw new IllegalStateException("idleTimeout < heartbeatInterval * 2");
                 }
-                if (h != heartbeat || t != heartbeatTimeout) {
+                if (h != heartbeat || t != idleTimeout) {
                     heartbeat = h;
-                    heartbeatTimeout = t;
+                    idleTimeout = t;
 
-                    stopHeartbeatTimer();
-                    startHeartbeatTimer();
+                    stopIdleCheckTimer();
+                    startIdleCheckTimer();
                 }
             }
         } catch (Throwable t) {
@@ -260,27 +259,23 @@ private long calculateLeastDuration(int time) {
         }
     }
 
-    private void startHeartbeatTimer() {
+    private void startIdleCheckTimer() {
         long tickDuration = calculateLeastDuration(heartbeat);
-        heartbeatTimer = new HashedWheelTimer(new NamedThreadFactory("dubbo-server-heartbeat", true), tickDuration,
+        idleCheckTimer = new HashedWheelTimer(new NamedThreadFactory("dubbo-server-idleCheck", true), tickDuration,
                 TimeUnit.MILLISECONDS, Constants.TICKS_PER_WHEEL);
-
         AbstractTimerTask.ChannelProvider cp = () -> unmodifiableCollection(HeaderExchangeServer.this.getChannels());
 
-        long heartbeatTick = calculateLeastDuration(heartbeat);
-        long heartbeatTimeoutTick = calculateLeastDuration(heartbeatTimeout);
-        HeartbeatTimerTask heartBeatTimerTask = new HeartbeatTimerTask(cp, heartbeatTick, heartbeat);
-        ReconnectTimerTask reconnectTimerTask = new ReconnectTimerTask(cp, heartbeatTimeoutTick, heartbeatTimeout);
+        long idleTimeoutTick = calculateLeastDuration(idleTimeout);
+        CloseTimerTask closeTimerTask = new CloseTimerTask(cp, idleTimeoutTick, idleTimeout);
 
         // init task and start timer.
-        heartbeatTimer.newTimeout(heartBeatTimerTask, heartbeatTick, TimeUnit.MILLISECONDS);
-        heartbeatTimer.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS);
+        idleCheckTimer.newTimeout(closeTimerTask, idleTimeoutTick, TimeUnit.MILLISECONDS);
     }
 
-    private void stopHeartbeatTimer() {
-        if (heartbeatTimer != null) {
-            heartbeatTimer.stop();
-            heartbeatTimer = null;
+    private void stopIdleCheckTimer() {
+        if (idleCheckTimer != null) {
+            idleCheckTimer.stop();
+            idleCheckTimer = null;
         }
     }
 
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/ReconnectTimerTask.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/ReconnectTimerTask.java
index 2b7dca552c8..3c0e9389db8 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/ReconnectTimerTask.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/ReconnectTimerTask.java
@@ -29,35 +29,30 @@ public class ReconnectTimerTask extends AbstractTimerTask {
 
     private static final Logger logger = LoggerFactory.getLogger(ReconnectTimerTask.class);
 
-    private final int heartbeatTimeout;
+    private final int idleTimeout;
 
-    ReconnectTimerTask(ChannelProvider channelProvider, Long heartbeatTimeoutTick, int heartbeatTimeout1) {
+    public ReconnectTimerTask(ChannelProvider channelProvider, Long heartbeatTimeoutTick, int idleTimeout) {
         super(channelProvider, heartbeatTimeoutTick);
-        this.heartbeatTimeout = heartbeatTimeout1;
+        this.idleTimeout = idleTimeout;
     }
 
     @Override
     protected void doTask(Channel channel) {
-        Long lastRead = lastRead(channel);
-        Long now = now();
-        if (lastRead != null && now - lastRead > heartbeatTimeout) {
-            if (channel instanceof Client) {
+        try {
+            Long lastRead = lastRead(channel);
+            Long now = now();
+            // check pong at client
+            if (lastRead != null && now - lastRead > idleTimeout) {
+                logger.warn("Close channel " + channel + ", because heartbeat read idle time out: "
+                        + idleTimeout + "ms");
                 try {
-                    logger.warn("Reconnect to remote channel " + channel.getRemoteAddress() + ", because heartbeat read idle time out: "
-                            + heartbeatTimeout + "ms");
                     ((Client) channel).reconnect();
-                } catch (Throwable t) {
-                    // do nothing
-                }
-            } else {
-                try {
-                    logger.warn("Close channel " + channel + ", because heartbeat read idle time out: "
-                            + heartbeatTimeout + "ms");
-                    channel.close();
-                } catch (Throwable t) {
-                    logger.warn("Exception when close channel " + channel, t);
+                } catch (Exception e) {
+                    logger.error(channel + "reconnect failed during idle time.", e);
                 }
             }
+        } catch (Throwable t) {
+            logger.warn("Exception when reconnect to remote channel " + channel.getRemoteAddress(), t);
         }
     }
 }

From dae90c673b96bfdf5e60974d98117c64a2e14851 Mon Sep 17 00:00:00 2001
From: xujingfeng <jingfeng.xjf@alibaba-inc.com>
Date: Mon, 21 Jan 2019 11:18:46 +0800
Subject: [PATCH 5/5] improve:change the scope of timer to static

---
 .../support/header/HeaderExchangeClient.java  | 23 +++++-----------
 .../support/header/HeaderExchangeServer.java  | 26 +++++--------------
 2 files changed, 13 insertions(+), 36 deletions(-)

diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java
index 4c821a99980..a28d53ec51a 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java
@@ -19,6 +19,7 @@
 import org.apache.dubbo.common.Constants;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.timer.HashedWheelTimer;
+import org.apache.dubbo.common.utils.Assert;
 import org.apache.dubbo.common.utils.NamedThreadFactory;
 import org.apache.dubbo.remoting.ChannelHandler;
 import org.apache.dubbo.remoting.Client;
@@ -42,12 +43,11 @@ public class HeaderExchangeClient implements ExchangeClient {
     private int heartbeat;
     private int idleTimeout;
 
-    private HashedWheelTimer idleCheckTimer;
+    private static HashedWheelTimer idleCheckTimer = new HashedWheelTimer(new NamedThreadFactory("dubbo-client-idleCheck", true), 1,
+            TimeUnit.SECONDS, Constants.TICKS_PER_WHEEL);
 
     public HeaderExchangeClient(Client client, boolean needHeartbeat) {
-        if (client == null) {
-            throw new IllegalArgumentException("client == null");
-        }
+        Assert.notNull(client, "Client can't be null");
         this.client = client;
         this.channel = new HeaderExchangeChannel(client);
         String dubbo = client.getUrl().getParameter(Constants.DUBBO_VERSION_KEY);
@@ -60,10 +60,7 @@ public HeaderExchangeClient(Client client, boolean needHeartbeat) {
         }
 
         if (needHeartbeat) {
-            long tickDuration = calculateLeastDuration(heartbeat);
-            idleCheckTimer = new HashedWheelTimer(new NamedThreadFactory("dubbo-client-idleCheck", true), tickDuration,
-                    TimeUnit.MILLISECONDS, Constants.TICKS_PER_WHEEL);
-            startIdleCheckTimer();
+            startIdleCheckTask();
         }
     }
 
@@ -177,7 +174,7 @@ public boolean hasAttribute(String key) {
         return channel.hasAttribute(key);
     }
 
-    private void startIdleCheckTimer() {
+    private void startIdleCheckTask() {
         AbstractTimerTask.ChannelProvider cp = () -> Collections.singletonList(HeaderExchangeClient.this);
 
         long heartbeatTick = calculateLeastDuration(heartbeat);
@@ -190,15 +187,7 @@ private void startIdleCheckTimer() {
         idleCheckTimer.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS);
     }
 
-    private void stopIdleCheckTimer() {
-        if (idleCheckTimer != null) {
-            idleCheckTimer.stop();
-            idleCheckTimer = null;
-        }
-    }
-
     private void doClose() {
-        stopIdleCheckTimer();
     }
 
     /**
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java
index 13cace0e66e..4609d2ab529 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java
@@ -22,6 +22,7 @@
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.timer.HashedWheelTimer;
+import org.apache.dubbo.common.utils.Assert;
 import org.apache.dubbo.common.utils.CollectionUtils;
 import org.apache.dubbo.common.utils.NamedThreadFactory;
 import org.apache.dubbo.remoting.Channel;
@@ -52,12 +53,11 @@ public class HeaderExchangeServer implements ExchangeServer {
     private int idleTimeout;
     private AtomicBoolean closed = new AtomicBoolean(false);
 
-    private HashedWheelTimer idleCheckTimer;
+    private static HashedWheelTimer idleCheckTimer = new HashedWheelTimer(new NamedThreadFactory("dubbo-server-idleCheck", true), 1,
+            TimeUnit.SECONDS, Constants.TICKS_PER_WHEEL);
 
     public HeaderExchangeServer(Server server) {
-        if (server == null) {
-            throw new IllegalArgumentException("server == null");
-        }
+        Assert.notNull(server, "server == null");
         this.server = server;
         this.heartbeat = server.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0);
         this.idleTimeout = server.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3);
@@ -65,7 +65,7 @@ public HeaderExchangeServer(Server server) {
             throw new IllegalStateException("idleTimeout < heartbeatInterval * 2");
         }
 
-        startIdleCheckTimer();
+        startIdleCheckTask();
     }
 
     public Server getServer() {
@@ -148,7 +148,6 @@ private void doClose() {
         if (!closed.compareAndSet(false, true)) {
             return;
         }
-        stopIdleCheckTimer();
     }
 
     @Override
@@ -215,8 +214,7 @@ public void reset(URL url) {
                     heartbeat = h;
                     idleTimeout = t;
 
-                    stopIdleCheckTimer();
-                    startIdleCheckTimer();
+                    startIdleCheckTask();
                 }
             }
         } catch (Throwable t) {
@@ -259,10 +257,7 @@ private long calculateLeastDuration(int time) {
         }
     }
 
-    private void startIdleCheckTimer() {
-        long tickDuration = calculateLeastDuration(heartbeat);
-        idleCheckTimer = new HashedWheelTimer(new NamedThreadFactory("dubbo-server-idleCheck", true), tickDuration,
-                TimeUnit.MILLISECONDS, Constants.TICKS_PER_WHEEL);
+    private void startIdleCheckTask() {
         AbstractTimerTask.ChannelProvider cp = () -> unmodifiableCollection(HeaderExchangeServer.this.getChannels());
 
         long idleTimeoutTick = calculateLeastDuration(idleTimeout);
@@ -272,11 +267,4 @@ private void startIdleCheckTimer() {
         idleCheckTimer.newTimeout(closeTimerTask, idleTimeoutTick, TimeUnit.MILLISECONDS);
     }
 
-    private void stopIdleCheckTimer() {
-        if (idleCheckTimer != null) {
-            idleCheckTimer.stop();
-            idleCheckTimer = null;
-        }
-    }
-
 }