¿Está bien usar una cadena como un objeto de bloqueo?

Necesito hacer una sección crítica en un área sobre la base de un conjunto finito de cadenas. Quiero que el bloqueo se comparta para la misma instancia de cadena, (algo similar aString.Intern enfoque).

Estoy considerando la siguiente implementación:

public class Foo
{
    private readonly string _s;
    private static readonly HashSet<string> _locks = new HashSet<string>();

    public Foo(string s)
    {
        _s = s;
        _locks.Add(s);
    }

    public void LockMethod()
    {
        lock(_locks.Single(l => l == _s))
        {
            ...
        }
    }
}

¿Hay algún problema con este enfoque? ¿Está bien bloquear un objeto de cadena de esta manera, y hay problemas de seguridad en el uso de la cadena?HashSet<string>?

¿Es mejor, por ejemplo, crear unDictionary<string, object> que crea un nuevo objeto de bloqueo para cada instancia de cadena?

Implementación final

Basándome en las sugerencias fui con la siguiente implementación:

public class Foo
{
    private readonly string _s;
    private static readonly ConcurrentDictionary<string, object> _locks = new ConcurrentDictionary<string, object>();

    public Foo(string s)
    {
        _s = s;
    }

    public void LockMethod()
    {
        lock(_locks.GetOrAdd(_s, _ => new object()))
        {
            ...
        }
    }
}

Respuestas a la pregunta(3)

Su respuesta a la pregunta