[SPARK-3106] Fix the race condition issue about Connection and ConnectionManager

The way to handle this is to make closed an AtomicBoolean and do a getAndSet.
If the result of getAndSet is false, which means closed was false on invocation, only then do the actual logic of close from earlier : it is a bug that all invocations of close was trying to do the same thing.

Essentially :
a) Change 
```var closed = false```
to
```var closed = new AtomicBoolean(false)```

b) Change close() to
```
def close() {
  val prev = closed.getAndSet(true)
  if (! prev) {
    closeImpl()
  }
}
```

Where closeImpl is a private method containing the logic from earlier close (except for the closed variable update).


This will ensure that failures in closeImpl will still result in connection being marked as close; and repeated invocations will not cause same code to be executed and other failures to surface (like missing id from map, etc).