### Summary

Within `AnsibleModule.run_command()`, prior to calling `subprocess.Popen`, it uses `os.environ.get()` to read some environment variables:

https://github.com/ansible/ansible/blob/v2.11.0/lib/ansible/module_utils/basic.py#L1947

After the `Popen` call, it deletes some environment variables that were added using `del os.environ[]`:

https://github.com/ansible/ansible/blob/v2.11.0/lib/ansible/module_utils/basic.py#L2091

Unfortunately, this is not thread-safe when Ansible hits Python 2 targets (eg. CentOS 7). The Python 2 standard library implements `.get()` non-atomically:
```python
    def get(self, key, failobj=None):
        if key not in self:
            return failobj
        return self[key]
```

This surfaces in Ansible primarily during the fact collection process in `module_utils/facts/hardware/linux.py`, where several threads in a `multiprocessing.pool.ThreadPool` call `run_process()` to collect block device information. When the race condition is hit, a `KeyError` is raised, breaking the mount point fact gathering and leaving the facts unavailable.

In our environment, when running against 1000+ CentOS 7 hosts, this race condition will be intermittently hit on only 1-2 hosts, making this difficult to troubleshoot. Because it's very hard to reproduce with fewer hosts, I created a script to demonstrate how the `os.environ` mutation is problematic: https://gist.github.com/agunnerson-ibm/b7a956d05095c5fad885295e2e31c9a4

Is it possible to refactor `run_command()` so that it makes a copy of `os.environ`, mutates the copy, and then passes it to `subprocess.Popen` via the `env=` kwarg? I believe that would fix this race condition and would remove the current implementation's need to back up and restore environment variables.

### Issue Type

Bug Report

### Component Name

module_utils/basic

### Ansible Version

```console
ansible [core 2.11.0]
  config file = None
  configured module search path = ['/home/jenkins/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.8/site-packages/ansible
  ansible collection location = /home/jenkins/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.8.2 (default, Feb 29 2020, 17:03:31) [GCC 9.2.0]
  jinja version = 2.11.1
  libyaml = False
```


### Configuration

```console
(none)
```


### OS / Environment

Controller:
* Alpine 3.11.2
* Python 3.8

Target hosts:
* CentOS 7.9
* Python 2.7

### Steps to Reproduce

* Run an empty playbook (in debug mode) that only gathers facts against a very large number of hosts.
* Intermittently, on a small number of hosts, mount point fact gathering will fail due to `KeyError: 'LC_ALL'`

### Expected Results

Fact gathering should not fail due to multi-threaded `os.environ` mutation

### Actual Results

Mount point fact gathering fails and mount point facts are not available


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct
if sep_idx > -1:
                        clean_args.append('%s=********' % arg[:sep_idx])
                        continue
                    else:
                        is_passwd = True
                arg = heuristic_log_sanitize(arg, self.no_log_values)
                clean_args.append(arg)
            self._clean = ' '.join(shlex_quote(arg) for arg in clean_args)
        return self._clean
    def _restore_signal_handlers(self):
        
        if PY2 and sys.platform != 'win32':
            signal.signal(signal.SIGPIPE, signal.SIG_DFL)
    def run_command(self, args, check_rc=False, close_fds=True, executable=None, data=None, binary_data=False, path_prefix=None, cwd=None,
                    use_unsafe_shell=False, prompt_regex=None, environ_update=None, umask=None, encoding='utf-8', errors='surrogate_or_strict',
                    expand_user_and_vars=True, pass_fds=None, before_communicate_callback=None, ignore_invalid_cwd=True):
        '''
        Execute a command, returns rc, stdout, and stderr.
        :arg args: is the command to run
            * If args is a list, the command will be run with shell=False.
            * If args is a string and use_unsafe_shell=False it will split args to a list and run with shell=False
            * If args is a string and use_unsafe_shell=True it runs with shell=True.
        :kw check_rc: Whether to call fail_json in case of non zero RC.
            Default False
        :kw close_fds: See documentation for subprocess.Popen(). Default True
        :kw executable: See documentation for subprocess.Popen(). Default None
        :kw data: If given, information to write to the stdin of the command
        :kw binary_data: If False, append a newline to the data.  Default False
        :kw path_prefix: If given, additional path to find the command in.
            This adds to the PATH environment variable so helper commands in