Java中Lock(synchronized和lock区别)

Java中Lock(synchronized和lock区别)

首先我们要明白,lock锁是后出的(1.5),肯定是弥补了部分的不足,一起认识下他们的区别


  1. synchronized是内置的关键字(功能统一),Lock锁是一个类,在java.util.concurrent.locks下的(功能可以改变的)。
  2. 由于synchronized是悲观锁,他会一直等等待对象头锁信息,阻塞的,不可被打断的。而Lock可以判断是否获取锁,并且可以不一定等待获取到锁。可以结束自己
  3. synchronized是自动上锁和自动释放锁,他会在编译class的时候产生两句原语:mintorenter,minorexit,代表上锁和推出锁。而Lock锁更像1.5之后Jmm中新增的lock和unLock(解决工作内存和主内存数据不一致),必须手动释放锁和加锁。
  4. synchronized是可重入的锁,不可以中断的,非公平的(处于性能考虑),Lock是可以决定重入锁,可以设置公平性,可以判断锁状态,如果没有能力获取锁则不会死锁,不会一直等待获取锁。
  5. synchronized是重量级锁,不适合大量代码。Lock可以,lock锁的粒度更细,分为读锁写锁等。

synchronized和Lock(官方注释:在Lock这个类中)

我们从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.

翻译

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

翻译

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

翻译

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

翻译

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.

翻译

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

翻译

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.

翻译

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.

翻译

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

翻译

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

Lock接口中定义的方法解读

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()尝试获取锁

/**
     * 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()释放锁

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

还有其他方法暂不介绍

在 一定时间内获取锁:

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

可中断锁:

void lockInterruptibly() throws InterruptedException;

猜你喜欢

转载自blog.csdn.net/qq_44112474/article/details/108567534