@Override
  public void run()
  {
    /**
     * Remember current time as the heartbeat start time. This is used for
     * calculating the delay for the next heartbeat.
     */
    this.lastHeartbeatStartTimeInSecs = System.currentTimeMillis() / 1000;

    Set<SFSession> sessionsToHeartbeat = new HashSet<SFSession>();

    // synchronously get a copy of the sessions from the global list
    synchronized (this)
    {
      sessionsToHeartbeat.addAll(sessions.keySet());
    }

    // heartbeat every session.
    for (SFSession session : sessionsToHeartbeat)
    {
      try
      {
        session.heartbeat();
      }
      catch (Throwable ex)
      {
        LOGGER.error("heartbeat error - message=" + ex.getMessage(), ex);
      }
    }

    /**
     * The following is synchronized with the methods to add or remove a
     * session so that we always make sure we have one heartbeat task scheduled
     * when there is any session left.
     */
    synchronized (this)
    {
      // schedule next heartbeat
      if (sessions.size() > 0)
      {
        LOGGER.debug("schedule next heartbeat run");

        scheduleHeartbeat();
      }
      else
      {
        LOGGER.debug("no need for heartbeat since no more sessions");

        // no need to heartbeat if no more session
        this.heartbeatFuture = null;
      }
    }
  }
@ Override public void run ( ) { this . lastHeartbeatStartTimeInSecs = System . currentTimeMillis ( ) / 1000 ; Set < SFSession > sessionsToHeartbeat = new HashSet < SFSession > ( ) ; synchronized ( this ) { sessionsToHeartbeat . addAll ( sessions . keySet ( ) ) ; } for ( SFSession session : sessionsToHeartbeat ) { try { session . heartbeat ( ) ; } catch ( Throwable ex ) { LOGGER . error ( "heartbeat error - message=" + ex . getMessage ( ) , ex ) ; } } synchronized ( this ) { if ( sessions . size ( ) > 0 ) { LOGGER . debug ( "schedule next heartbeat run" ) ; scheduleHeartbeat ( ) ; } else { LOGGER . debug ( "no need for heartbeat since no more sessions" ) ; this . heartbeatFuture = null ; } } }
Run heartbeat: for each session send a heartbeat request and schedule
next heartbeat as long as there are sessions left.
<p>
Notice that the synchronization is only around the code that visits the
global sessions map and the code that schedules
next heartbeat, but not around the heartbeat calls for each session in
order to minimize the chance of blocking the adding of a session by
performing the heartbeats. This is because adding a session is called from
JDBC connection creation call which directly affects application
performance.