Lock in Java (the difference between synchronized and lock)

Lock in Java (the difference between synchronized and lock)

First of all, we must understand that the lock lock is later (1.5), which must make up for some of the shortcomings. Let's understand the difference between them.


  1. Synchronized is a built-in keyword (unified functions), Lock is a class, under java.util.concurrent.locks (functions can be changed).
  2. Since synchronized is a pessimistic lock, he will always wait for the object head lock information, which is blocked and cannot be interrupted. And Lock can determine whether to acquire the lock, and may not necessarily wait for the lock to be acquired. Can end oneself
  3. Synchronized is automatic lock and automatic release lock, it will generate two primitives when compiling the class: mintorenter, minorexit, representing lock and release lock. The Lock lock is more like the new lock and unLock in Jmm after 1.5 (to solve the inconsistency of the working memory and the main memory data), the lock must be released and locked manually.
  4. Synchronized is a reentrant lock that cannot be interrupted and is unfair (for performance considerations). Lock can determine reentrant locks, set fairness, and judge the lock status. If there is no ability to acquire the lock, it will not deadlock. , Will not wait for the lock to be acquired.
  5. Synchronized is a heavyweight lock, not suitable for large amounts of code. Lock can be, the granularity of lock lock is more fine, divided into read lock write lock and so on.

Synchronized and Lock (official note: in the Lock class)

We learn from the class annotations of 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.

translation

我们实现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}.

translation

锁是什么东西?锁是多线程环境下,对共享资源的控制访问的一种工具
通常,锁提供对以下内容的资源的独占访问权
同一时间内,这个锁只允许第一个获的它的人,去访问共享资源
但是,有一些锁允许并发的访问资源。如读写锁(这里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.
 *

translation

使用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.

translation

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.

translation

随着灵活性的增加,消除块结构锁(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)}).

translation

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.

translation

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.

translation

请注意: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.

translation

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

Interpretation of the methods defined in the Lock interface

lock() acquire lock

 /**
     * 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() tries to acquire the lock

/**
     * 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
      }
 此方式可以确保只有获取锁的人才能释放锁
 如果没有获得锁,则不可以释放锁

unlock() release the lock

/**
     * 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实现类可以限制哪些线程可以释放锁
通常只有持有锁的线程才能释放
违反规定的话会抛出(未检查的)异常
任何异常都需要被记录下来

There are other methods not introduced yet

Acquire the lock within a certain period of time:

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

Interruptible lock:

void lockInterruptibly() throws InterruptedException;

Guess you like

Origin blog.csdn.net/qq_44112474/article/details/108567534