NIFI-9217 - avoid deadlock on cluster operation (#5390)

diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/leader/election/CuratorLeaderElectionManager.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/leader/election/CuratorLeaderElectionManager.java
index 99ac506..5fe8153 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/leader/election/CuratorLeaderElectionManager.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/leader/election/CuratorLeaderElectionManager.java
@@ -64,10 +64,10 @@
 
     private volatile boolean stopped = true;
 
-    private final Map<String, LeaderRole> leaderRoles = new HashMap<>();
-    private final Map<String, RegisteredRole> registeredRoles = new HashMap<>();
+    private final ConcurrentMap<String, LeaderRole> leaderRoles = new ConcurrentHashMap<>();
+    private final ConcurrentMap<String, RegisteredRole> registeredRoles = new ConcurrentHashMap<>();
 
-    private final Map<String, TimedBuffer<TimestampedLong>> leaderChanges = new HashMap<>();
+    private final ConcurrentMap<String, TimedBuffer<TimestampedLong>> leaderChanges = new ConcurrentHashMap<>();
     private final TimedBuffer<TimestampedLongAggregation> pollTimes = new TimedBuffer<>(TimeUnit.SECONDS, 300, new CountSumMinMaxAccess());
     private final ConcurrentMap<String, String> lastKnownLeader = new ConcurrentHashMap<>();
 
@@ -221,16 +221,16 @@
         return "CuratorLeaderElectionManager[stopped=" + isStopped() + "]";
     }
 
-    private synchronized LeaderRole getLeaderRole(final String roleName) {
+    private LeaderRole getLeaderRole(final String roleName) {
         return leaderRoles.get(roleName);
     }
 
-    private synchronized void onLeaderChanged(final String roleName) {
+    private void onLeaderChanged(final String roleName) {
         final TimedBuffer<TimestampedLong> buffer = leaderChanges.computeIfAbsent(roleName, key -> new TimedBuffer<>(TimeUnit.HOURS, 24, new LongEntityAccess()));
         buffer.add(new TimestampedLong(1L));
     }
 
-    public synchronized Map<String, Integer> getLeadershipChangeCount(final long duration, final TimeUnit unit) {
+    public Map<String, Integer> getLeadershipChangeCount(final long duration, final TimeUnit unit) {
         final Map<String, Integer> leadershipChangesPerRole = new HashMap<>();
 
         for (final Map.Entry<String, TimedBuffer<TimestampedLong>> entry : leaderChanges.entrySet()) {
@@ -301,48 +301,57 @@
         return participantId;
     }
 
-    private synchronized void registerPollTime(final long nanos) {
-        pollTimes.add(TimestampedLongAggregation.newValue(nanos));
+    private void registerPollTime(final long nanos) {
+        synchronized (pollTimes) {
+            pollTimes.add(TimestampedLongAggregation.newValue(nanos));
+        }
     }
 
-    public synchronized long getAveragePollTime(final TimeUnit timeUnit) {
-        final TimestampedLongAggregation.TimestampedAggregation aggregation = pollTimes.getAggregateValue(0L).getAggregation();
-        if (aggregation == null || aggregation.getCount() == 0) {
-            return 0L;
+    public long getAveragePollTime(final TimeUnit timeUnit) {
+        final long averageNanos;
+        synchronized (pollTimes) {
+            final TimestampedLongAggregation.TimestampedAggregation aggregation = pollTimes.getAggregateValue(0L).getAggregation();
+            if (aggregation == null || aggregation.getCount() == 0) {
+                return 0L;
+            }
+            averageNanos = aggregation.getSum() / aggregation.getCount();
         }
-
-        final long averageNanos = aggregation.getSum() / aggregation.getCount();
         return timeUnit.convert(averageNanos, TimeUnit.NANOSECONDS);
     }
 
-    public synchronized long getMinPollTime(final TimeUnit timeUnit) {
-        final TimestampedLongAggregation.TimestampedAggregation aggregation = pollTimes.getAggregateValue(0L).getAggregation();
-        if (aggregation == null) {
-            return 0L;
+    public long getMinPollTime(final TimeUnit timeUnit) {
+        final long minNanos;
+        synchronized (pollTimes) {
+            final TimestampedLongAggregation.TimestampedAggregation aggregation = pollTimes.getAggregateValue(0L).getAggregation();
+            if (aggregation == null) {
+                return 0L;
+            }
+            minNanos = aggregation.getMin();
         }
-
-        final long minNanos = aggregation.getMin();
         return timeUnit.convert(minNanos, TimeUnit.NANOSECONDS);
     }
 
-    public synchronized long getMaxPollTime(final TimeUnit timeUnit) {
-        final TimestampedLongAggregation.TimestampedAggregation aggregation = pollTimes.getAggregateValue(0L).getAggregation();
-        if (aggregation == null) {
-            return 0L;
+    public long getMaxPollTime(final TimeUnit timeUnit) {
+        final long maxNanos;
+        synchronized (pollTimes) {
+            final TimestampedLongAggregation.TimestampedAggregation aggregation = pollTimes.getAggregateValue(0L).getAggregation();
+            if (aggregation == null) {
+                return 0L;
+            }
+            maxNanos = aggregation.getMax();
         }
-
-        final long maxNanos = aggregation.getMax();
         return timeUnit.convert(maxNanos, TimeUnit.NANOSECONDS);
     }
 
     @Override
-    public synchronized long getPollCount() {
-        final TimestampedLongAggregation.TimestampedAggregation aggregation = pollTimes.getAggregateValue(0L).getAggregation();
-        if (aggregation == null) {
-            return 0L;
+    public long getPollCount() {
+        synchronized (pollTimes) {
+            final TimestampedLongAggregation.TimestampedAggregation aggregation = pollTimes.getAggregateValue(0L).getAggregation();
+            if (aggregation == null) {
+                return 0L;
+            }
+            return aggregation.getCount();
         }
-
-        return aggregation.getCount();
     }
 
     /**