Recientemente, encontré algunos escenarios de alta concurrencia en el trabajo que requieren bloqueo para garantizar la corrección de la lógica comercial, y el rendimiento después del bloqueo no debe verse demasiado afectado. La idea inicial es bloquear los datos a través de palabras clave, como marcas de tiempo e ID, asegurando así la concurrencia de diferentes tipos de procesamiento de datos. La granularidad de bloqueo proporcionada por la propia API de Java es demasiado grande, y es difícil satisfacer estas necesidades al mismo tiempo, así que yo mismo escribí varias extensiones simples ...
1. Bloqueo de segmento
Basándose en la idea de segmentación de concurrenthashmap, se crea un cierto número de bloqueos y, al usarla, el bloqueo correspondiente se devuelve de acuerdo con la tecla. Este es el rendimiento más simple y más alto y, en última instancia, la estrategia de bloqueo entre varias implementaciones. El código es el siguiente:
/*** Bloqueo de segmento, el sistema proporciona un cierto número de bloqueos originales, obtenga el bloqueo correspondiente en función del valor hash del objeto entrante y agregue el bloqueo* Nota: ¡Si el valor hash del objeto que se bloquea, puede hacer que el bloqueo no pueda liberarse con éxito! */public class segmentLock <T> {private entero segmentos = 16; // Número predeterminado de segmentos Private Final HashMap <Integer, ReentRantlock> LockMap = new HashMap <> (); público segmentLock () {init (nulo, falso); } público segmentLock (recuentos de enteros, boolean fair) {init (cuenta, justa); } private void init (recuento de enteros, boolean fair) {if (Counts! = null) {segments = Counts; } para (int i = 0; i <segmentos; i ++) {LockMap.put (i, nuevo reentrantlock (justo)); }} Public void Lock (T tecla) {ReentrantLock Lock = LockMap.get ((Key.HashCode () >>> 1) % segmentos); Lock.lock (); } Public void desbloock (t key) {reentrantlock lock = listmap.get ((key.hashcode () >>> 1) % segmentos); Lock.unlock (); }}2. Lock Hash
La segunda estrategia de bloqueo desarrollada en función del bloqueo segmentado anterior es lograr un verdadero bloqueo de grano fino. Cada objeto con un valor hash diferente puede obtener su propio bloqueo independiente. En la prueba, cuando el código bloqueado se ejecuta rápidamente, la eficiencia es aproximadamente un 30% más lenta que el bloqueo del segmento. Si hay una operación que requiere mucho tiempo, la sensación de rendimiento debería ser mejor. El código es el siguiente:
HASHLOCK de clase pública <T> {private boolean isfair = false; privado final segmentlock <T> segmentLock = new SegmentLock <> (); // Segmento bloqueo Private final concurrenthashmap <t, LockInfo> LockMap = new concurrenthashmap <> (); public hastlock () {} public Public Hashlock (boolean fair) {isfair = jair; } Public void Lock (T Key) {LockInfo Lockinfo; segmentLock.lock (clave); intente {LockInfo = LockMap.get (Key); if (LockInfo == NULL) {LockInfo = new LockInfo (isfair); LockMap.put (tecla, LockInfo); } else {lockinfo.count.incrementandget (); }} finalmente {segmentLock.unlock (clave); } Lockinfo.lock.lock (); } public void desbloock (t key) {LockInfo LockInfo = LockMap.get (Key); if (lockinfo.count.get () == 1) {segmentLock.lock (clave); intente {if (lockinfo.count.get () == 1) {LockMap.Remove (Key); }} finalmente {segmentLock.unlock (clave); }} Lockinfo.count.DecrementAndget (); Lockinfo.unlock (); } Clase estática privada LockInfo {Public Reentrantlock Lock; público atomicInteger count = new AtomicInteger (1); Lockinfo privado (boolean fair) {this.lock = new Reentrantlock (justo); } public void Lock () {this.lock.lock (); } public void desbloock () {this.lock.unlock (); }}}3. Bloque de referencia débil
Las cerraduras hash siempre son defectuosas porque se introducen las cerraduras segmentadas para garantizar la sincronización de la creación y destrucción de cerraduras, por lo que se escribió un tercer bloqueo para buscar un mejor rendimiento y cerraduras de grano más fino. La idea de este bloqueo es crear una cerradura con la ayuda de referencias débiles en Java, y entregar la destrucción de la cerradura a la recolección de basura de JVM para evitar un consumo adicional.
Es un poco lamentable que, debido a que concurrenthashmap se usa como contenedor de bloqueo, no puede deshacerse de las cerraduras segmentadas. El rendimiento de esta cerradura es aproximadamente un 10% más rápido que el del hashlock. Código de bloqueo:
/*** Bloque de referencia débil, que proporciona una función de bloqueo independiente para cada hash*/clase pública de Deakhashlock <T> {private concurrenthashmap <t, débillockref <t, reentrantlock >> listmap = nuevo concurrenthashmap <> (); reference privadoqueue <Reentrantlock> queue = new RefectionQueue <> (); public reentrantlock get (t key) {if (lockmap.size ()> 1000) {ClearEmptyRef (); } WeakReference <Reentrantlock> LockRef = LockMap.get (Key); ReentrantLock Lock = (LockRef == NULL? NULL: LockRef.get ()); while (Lock == NULL) {LOCKMAP.PUTIFABSENT (Key, New WeakLockRef <> (new ReentRantLock (), cola, tecla)); Lockref = LockMap.get (tecla); bloqueo = (lockref == null? null: lockref.get ()); if (bloqueo! = null) {return Lock; } ClearEmptyRef (); } bloqueo de retorno; } @Suppleswarnings ("sin control") privado void clearEmtyRef () {referencia <? extiende reentrantlock> ref; while ((ref = queue.poll ())! = null) {débillockref <t ,? extiende reentrantlock> débillockref = (débillockref <t, "extiende reentrantlock>) ref; LockMap.Remove (débillockref.key); }} Clase final estática privada débillockref <t, k> extiende la referencia débil <K> {final t final; privado débillockref (k reference, referencequeue <? Super K> Q> Q> Q, T Key) {super (referente, q); this.key = key; }}}posdata
Al principio quería usar Locksupport y AQS para implementar cerraduras de grano fino. Como escribí, descubrí que las cosas que estaba implementando no eran muy diferentes de esas cerraduras de Java nativas, así que renuncié a la encapsulación de las propias cerraduras de Java, que perdió mucho tiempo.
De hecho, después de implementar estas cerraduras de grano fino, tenemos nuevas ideas, como enviar datos a hilos especiales a través de ideas de segmentación, lo que puede reducir el tiempo de bloqueo de una gran cantidad de hilos y dejarlos a futuras exploración ...