Bloquear en Java (la diferencia entre sincronizado y bloqueo)

Bloquear en Java (la diferencia entre sincronizado y bloqueo)

En primer lugar, debemos entender que el bloqueo de la cerradura es posterior (1.5), lo que debe suplir algunas de las deficiencias, entendamos la diferencia entre ellas.


  1. Synchronized es una palabra clave incorporada (funciones unificadas), Lock es una clase, en java.util.concurrent.locks (las funciones se pueden cambiar).
  2. Dado que sincronizado es un bloqueo pesimista, siempre esperará la información del bloqueo del cabezal del objeto, que está bloqueado y no se puede interrumpir. Y Lock puede determinar si debe adquirir el candado y no necesariamente esperar a que se obtenga el candado. Puede acabar con uno mismo
  3. Sincronizado es bloqueo automático y bloqueo de liberación automática, generará dos primitivas al compilar la clase: mintorenter, minorexit, que representa bloqueo y liberación de bloqueo. El bloqueo de bloqueo se parece más al nuevo bloqueo y desbloqueo en Jmm después de 1.5 (para resolver la inconsistencia de la memoria de trabajo y los datos de la memoria principal), el bloqueo debe liberarse y bloquearse manualmente.
  4. Sincronizado es un bloqueo reentrante que no se puede interrumpir y es injusto (por consideraciones de rendimiento). El bloqueo puede determinar los bloqueos reentrantes, establecer la equidad y juzgar el estado del bloqueo. Si no se puede adquirir el bloqueo, no se interbloqueará. , No esperará a que se adquiera la cerradura.
  5. Synchronized es un candado pesado, no apto para grandes cantidades de código. El bloqueo puede ser, la granularidad del bloqueo de bloqueo es más fina, dividida en bloqueo de lectura, bloqueo de escritura, etc.

Synchronized y Lock (nota oficial: en la clase Lock)

Aprendemos de las anotaciones de clase de java.util.concurrent.locks.Lock

/* {@code Lock} implementations provide more extensive locking
 * operations than can be obtained using {@code synchronized} methods
 * and statements.  They allow more flexible structuring, may have
 * quite different properties, and may support multiple associated
 * {@link Condition} objects.

Traducción

我们实现Lock接口的锁讲比synchronized提供更灵活的声明和方法 (声明可以是公平或非公平,方法可以新增tryLock)
Lock允许更灵活的结构,完全不同的属性,并且可以关联多个对象(synchronized的属性和方法是规定好的)

 /* <p>A lock is a tool for controlling access to a shared resource by
 * multiple threads. Commonly, a lock provides exclusive access to a
 * shared resource: only one thread at a time can acquire the lock and
 * all access to the shared resource requires that the lock be
 * acquired first. However, some locks may allow concurrent access to
 * a shared resource, such as the read lock of a {@link ReadWriteLock}.

Traducción

锁是什么东西?锁是多线程环境下,对共享资源的控制访问的一种工具
通常,锁提供对以下内容的资源的独占访问权
同一时间内,这个锁只允许第一个获的它的人,去访问共享资源
但是,有一些锁允许并发的访问资源。如读写锁(这里Lock把锁粒度细分了)
 /* <p>The use of {@code synchronized} methods or statements provides
 * access to the implicit monitor lock associated with every object, but
 * forces all lock acquisition and release to occur in a block-structured way:
 * when multiple locks are acquired they must be released in the opposite
 * order, and all locks must be released in the same lexical scope in which
 * they were acquired.
 *

Traducción

使用synchronized关键词可提供对每个对象的监视和访问
但是强制所有的锁的获取和释放都在同步块总执行的
当获取多个锁的时候他们的释放顺序和获取顺序相反
这些锁必须在获取他们相同的语法范围内释放

/* <p>While the scoping mechanism for {@code synchronized} methods
 * and statements makes it much easier to program with monitor locks,
 * and helps avoid many common programming errors involving locks,
 * there are occasions where you need to work with locks in a more
 * flexible way. For example, some algorithms for traversing
 * concurrently accessed data structures require the use of
 * &quot;hand-over-hand&quot; or &quot;chain locking&quot;: you
 * acquire the lock of node A, then node B, then release A and acquire
 * C, then release B and acquire D and so on.  Implementations of the
 * {@code Lock} interface enable the use of such techniques by
 * allowing a lock to be acquired and released in different scopes,
 * and allowing multiple locks to be acquired and released in any
 * order.

Traducción

synchronized的作用域机制使得我们使用监视器锁来控制共享变量更加容易
避免我们许多编程错误(不需要我们手动上锁和释放锁)
不过在某些灵活的加锁场景下,需要灵活的方式 (可能会突破加&释放锁的范围)
例如:一些遍历算法并发访问的数据结构需要使用,移交或锁链;
你先获取节点A的锁,再获取节点B的锁,然后释放A并获取C的锁,然后释放B并获取D的锁
以此类推,如果实现lock接口,允许在不同的范围内获取锁和释放锁,允许多个锁释放可以不按照加锁的顺序

 /* <p>With this increased flexibility comes additional
 * responsibility. The absence of block-structured locking removes the
 * automatic release of locks that occurs with {@code synchronized}
 * methods and statements. In most cases, the following idiom
 * should be used:
 * Lock l = ...;
 * l.lock();
 * try {
 *   // access the resource protected by this lock
 * } finally {
 *   l.unlock();
 * }
 * When locking and unlocking occur in different scopes, care must be
 * taken to ensure that all code that is executed while the lock is
 * held is protected by try-finally or try-catch to ensure that the
 * lock is released when necessary.

Traducción

随着灵活性的增加,消除块结构锁(synchronized)
则移除了自动加锁和释放锁的方法和声明过程。
我们大多数可以这样实现手动加锁释放锁
Lock l = ......;  // 实现Lock接口的实现类
l.lock();  		  // 加锁
try{
				  // 需要加锁的资源
}finally(){
	l.lock() 	  // 释放锁
}
当解锁和加锁在不同的范围时,
必须关心确定我们加锁的代码受try finally保护
那样我们在必要的时候可以释放锁
 /* <p>{@code Lock} implementations provide additional functionality
 * over the use of {@code synchronized} methods and statements by
 * providing a non-blocking attempt to acquire a lock ({@link
 * #tryLock()}), an attempt to acquire the lock that can be
 * interrupted ({@link #lockInterruptibly}, and an attempt to acquire
 * the lock that can timeout ({@link #tryLock(long, TimeUnit)}).

Traducción

lock利用非阻塞的tyLock()去尝试获取锁的方法
比synchronized提供了更多的方法和声明
tryLock方式是尝试获取一个可被中断的锁
尝试获取一个超时的锁
 /* <p>A {@code Lock} class can also provide behavior and semantics
 * that is quite different from that of the implicit monitor lock,
 * such as guaranteed ordering, non-reentrant usage, or deadlock
 * detection. If an implementation provides such specialized semantics
 * then the implementation must document those semantics.

Traducción

Lock锁可以提供的行为和语义和synchronized(monitor lock)有很大不同
例如;保证顺序,不可重入使用,死锁检测。
如果使用了这些专门的语义,则必须记录这些语义(我的理解是需要了解这些语义再使用,可以当作参数使用)
 /* <p>Note that {@code Lock} instances are just normal objects and can
 * themselves be used as the target in a {@code synchronized} statement.
 * Acquiring the
 * monitor lock of a {@code Lock} instance has no specified relationship
 * with invoking any of the {@link #lock} methods of that instance.
 * It is recommended that to avoid confusion you never use {@code Lock}
 * instances in this way, except within their own implementation.

Traducción

请注意:Lock锁也仅仅是一个普通对象的实例
也是能够被synchronized代码块包裹的
synchronized的隐式监视器和实例的lock方法并没有特殊的指定的关系
为了避免混淆,避免用这个方法使用Lock实例
 /* <p>Except where noted, passing a {@code null} value for any
 * parameter will result in a {@link NullPointerException} being
 * thrown.

Traducción

除非特殊说明,否则任何一个传入值为空引用都会抛出一个空指针的异常

Interpretación de los métodos definidos en la interfaz Lock

bloquear () adquirir bloqueo

 /**
     * Acquires the lock.
     *
     * <p>If the lock is not available then the current thread becomes
     * disabled for thread scheduling purposes and lies dormant until the
     * lock has been acquired.
     *
     * <p><b>Implementation Considerations</b>
     *
     * <p>A {@code Lock} implementation may be able to detect erroneous use
     * of the lock, such as an invocation that would cause deadlock, and
     * may throw an (unchecked) exception in such circumstances.  The
     * circumstances and the exception type must be documented by that
     * {@code Lock} implementation.
     */
如果锁不可用,则对于调度程序来所当前线程会变成禁用状态
并且休眠,直到,这个锁可用为止
<注意事项>
使用Lock锁可能去检查像死锁这样的错误
有些情况下会抛出一个异常
在这些情况下需要告诉实现者这个异常

tryLock () intenta adquirir el bloqueo

/**
     * Acquires the lock only if it is free at the time of invocation.
     *
     * <p>Acquires the lock if it is available and returns immediately
     * with the value {@code true}.
     * If the lock is not available then this method will return
     * immediately with the value {@code false}.
     *
     * <p>A typical usage idiom for this method would be:
     *  <pre> {@code
     * Lock lock = ...;
     * if (lock.tryLock()) {
     *   try {
     *     // manipulate protected state
     *   } finally {
     *     lock.unlock();
     *   }
     * } else {
     *   // perform alternative actions
     * }}</pre>
     *
     * This usage ensures that the lock is unlocked if it was acquired, and
     * doesn't try to unlock if the lock was not acquired.
     *
     * @return {@code true} if the lock was acquired and
     *         {@code false} otherwise
     */
如果在调用的时候这个锁是空闲的才去获得这个锁
如果这个锁可以获得,则获得锁立即返回true
如果这个锁不可以获得,立马返回false
典型用法如下
      Lock lock = ...;
      if (lock.tryLock()) {
       try {
          // manipulate protected state
        } finally {
          lock.unlock();
        }
      } else {
        // perform alternative actions
      }
 此方式可以确保只有获取锁的人才能释放锁
 如果没有获得锁,则不可以释放锁

desbloquear () liberar el bloqueo

/**
     * Releases the lock.
     *
     * <p><b>Implementation Considerations</b>
     *
     * <p>A {@code Lock} implementation will usually impose
     * restrictions on which thread can release a lock (typically only the
     * holder of the lock can release it) and may throw
     * an (unchecked) exception if the restriction is violated.
     * Any restrictions and the exception
     * type must be documented by that {@code Lock} implementation.
     */
Lock实现类可以限制哪些线程可以释放锁
通常只有持有锁的线程才能释放
违反规定的话会抛出(未检查的)异常
任何异常都需要被记录下来

Hay otros métodos que aún no se han introducido

Adquirir el candado dentro de un cierto período de tiempo:

boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

Bloqueo interrumpible:

void lockInterruptibly() throws InterruptedException;

Supongo que te gusta

Origin blog.csdn.net/qq_44112474/article/details/108567534
Recomendado
Clasificación