Java并发编程之ReentrantLock 灰太狼 2022-06-02 04:43 187阅读 0赞 * **public class ReentrantLock extends Object implements Lock, Serializable** > ***A reentrant mutual exclusion Lock with the same basic behavior and semantics as the implicit monitor lock accessed using synchronized methods and statements, but with extended capabilities.*** ReentrantLock最佳实践,调用lock方法之后,紧跟异常处理**try…catch…finally**模块,**finally**逻辑中调用unlock方法 class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } } } ### **Synchronization vs ReentrantLock** ### ![这里写图片描述][SouthEast] > **Synchronization** * 1、Synchronization同步机制中,线程通过获取共享对象监视器的方式来获取共享对象的访问权限。 * 2、Synchronization同步机制中,无法中断共享对象池上的其他等待线程 * 3、Synchronization同步机制中,可能出现“死锁”现象,如A等待B,B同时也在等待A * 4、Synchronization同步机制中,阻塞线程可能出现“饿死”现象,即:永远无法获得等待资源。可能出现一个线程正处于等待暂停状态,而另一个线程却获取到了共享对象的访问权限,导致等待线程一直无法获取到等待资源 > **ReentrantLock** * 1、在ReentrantLock机制中,ReentrantLock 本身就是一个Java对象,所以多线程通过锁定reentrantlock对象实例来获取共享对象的访问权限 * 2、ReentrantLock提供了中断锁池上的其他等待线程的机制。 * 3、通过reentrant(重入机制),我们可以通过创建非阻塞线程的方式来减少“死锁”的可能性。但随之而来的是另一个可能要面临的“活锁”问题:如,非阻塞线程A反复尝试获取共享对象访问权限,但却一直无法成功获取(原因是:共享资源正由另一个线程B占有,但当前线程B也一直试图获取另一个由之前线程A占有的reentrant锁对象) * 4、ReentrantLock提供了一种公平机制,确保等待时间更长的线程优先获取到共享资源访问权限 #### **ReentrantLock提供方法列表如下:** #### ![这里写图片描述][SouthEast 1] <table> <thead> <tr> <th>方法</th> <th>方法说明</th> </tr> </thead> <tbody> <tr> <td>lock()</td> <td>By invoke this method Thread lock the Lock instance. If Lock is already locked. Thread is waiting for Jock until it unlocked.</td> </tr> <tr> <td>trylock()</td> <td>upon invoking this method. Thread lock the instance if it is not locked. Lock is locked thread returns,thread not going to wait, unblocking nature</td> </tr> <tr> <td>getHoldCount()</td> <td>It returns the number of holds of lock for the given thread.</td> </tr> <tr> <td>lockInterruptibly()</td> <td>upon invoking this method Thread lock the instance if lock is not locked and thread is not interrupted by otherThread</td> </tr> <tr> <td>trylock(long timeout,TimeUnit timeUnit)</td> <td>upon invoking this method.Thread lock the instance if it is not locked. If Lock is locked Thread block for time unit specified. Then returns.</td> </tr> <tr> <td>unlock()</td> <td>unlock the Lock instance</td> </tr> </tbody> </table> ### **示例** ### * 账户转账,定义账户类: public class Account { private ReentrantLock implicitLock = new ReentrantLock(); private String name; private Integer balance = 10000; public ReentrantLock getImplicitLock() { return implicitLock; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getBalance() { return balance; } public void setBalance(Integer blance) { this.balance = blance; } public boolean debit(Integer amount) { if (amount > balance) { System.out.println(Thread.currentThread().getName() + " :: " + name + " says ::" + amount + " grater than current balance"); return false; } balance = balance - amount; System.out.println(Thread.currentThread().getName() + " :: " + name + " says ::" + amount + " Debited Success Fully"); return true; } public void credit(Integer amount) { balance = balance + amount; System.out.println(Thread.currentThread().getName() + " :: " + name + " says ::" + amount + " Credited Success Fully"); } } * 转账测试 public class AccountTransfer { private ReentrantLock lock = new ReentrantLock(); public void transfer(Account from, Account to, Integer amount) { boolean transfer = false; try { if (lock.tryLock()) { System.out.println(Thread.currentThread().getName() + " says acquire lock"); boolean flag = from.debit(amount); if (flag) { to.credit(amount); } System.out.println(Thread.currentThread().getName() + " :: " + from.getName() + " says :: now balance is " + from.getBalance()); System.out.println(Thread.currentThread().getName() + " :: " + to.getName() + " says :: now balance is " + to.getBalance()); transfer = true; } else { System.out.println(Thread.currentThread().getName() + " says fail to acquire both lock Try again"); transfer(from, to, amount);//try again } } catch (Exception ex) { ex.printStackTrace(); } finally { if (transfer) { lock.unlock(); } } } public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(3); Account from = new Account(); from.setBalance(20000); from.setName("Tom"); Account to = new Account(); to.setName("Jerry"); System.out.println(String.format("%s initial balance %s", from.getName(), from.getBalance())); System.out.println(String.format("%s initial balance %s", to.getName(), to.getBalance())); AccountTransfer transfer = new AccountTransfer(); Runnable a = () -> { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } transfer.transfer(from, to, 200); System.out.println(Thread.currentThread().getName() + " says :: Transfer successfully"); }; Runnable b = () -> { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } transfer.transfer(to, from, 1000); System.out.println(Thread.currentThread().getName() + " says :: Transfer successfully"); }; for (int i = 0; i < 4; i++) { service.submit(a); service.submit(b); } } } * * 执行结果: > Tom initial balance 20000 > Jerry initial balance 10000 > pool-1-thread-2 says acquire lock > pool-1-thread-2 :: Jerry says ::1000 Debited Success Fully > pool-1-thread-2 :: Tom says ::1000 Credited Success Fully > pool-1-thread-2 :: Jerry says :: now balance is 9000 > pool-1-thread-2 :: Tom says :: now balance is 21000 > pool-1-thread-2 says :: Transfer successfully > pool-1-thread-3 says acquire lock > pool-1-thread-3 :: Tom says ::200 Debited Success Fully > pool-1-thread-3 :: Jerry says ::200 Credited Success Fully > pool-1-thread-3 :: Tom says :: now balance is 20800 > pool-1-thread-3 :: Jerry says :: now balance is 9200 > pool-1-thread-3 says :: Transfer successfully > pool-1-thread-1 says acquire lock > pool-1-thread-1 :: Tom says ::200 Debited Success Fully > pool-1-thread-1 :: Jerry says ::200 Credited Success Fully > pool-1-thread-1 :: Tom says :: now balance is 20600 > pool-1-thread-1 :: Jerry says :: now balance is 9400 > pool-1-thread-1 says :: Transfer successfully > pool-1-thread-1 says acquire lock > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-3 says fail to acquire both lock Try again > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-1 :: Jerry says ::1000 Debited Success Fully > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-3 says fail to acquire both lock Try again > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-1 :: Tom says ::1000 Credited Success Fully > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-3 says fail to acquire both lock Try again > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-1 :: Jerry says :: now balance is 8400 > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-1 :: Tom says :: now balance is 21600 > pool-1-thread-3 says fail to acquire both lock Try again > pool-1-thread-3 says acquire lock > pool-1-thread-1 says :: Transfer successfully > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-3 :: Tom says ::200 Debited Success Fully > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-3 :: Jerry says ::200 Credited Success Fully > pool-1-thread-3 :: Tom says :: now balance is 21400 > pool-1-thread-3 :: Jerry says :: now balance is 8600 > pool-1-thread-3 says :: Transfer successfully > pool-1-thread-2 says fail to acquire both lock Try again > pool-1-thread-2 says acquire lock > pool-1-thread-2 :: Jerry says ::1000 Debited Success Fully > pool-1-thread-2 :: Tom says ::1000 Credited Success Fully > pool-1-thread-2 :: Jerry says :: now balance is 7600 > pool-1-thread-2 :: Tom says :: now balance is 22400 > pool-1-thread-2 says :: Transfer successfully > pool-1-thread-1 says acquire lock > pool-1-thread-1 :: Tom says ::200 Debited Success Fully > pool-1-thread-1 :: Jerry says ::200 Credited Success Fully > pool-1-thread-1 :: Tom says :: now balance is 22200 > pool-1-thread-1 :: Jerry says :: now balance is 7800 > pool-1-thread-1 says :: Transfer successfully > pool-1-thread-3 says acquire lock > pool-1-thread-3 :: Jerry says ::1000 Debited Success Fully > pool-1-thread-3 :: Tom says ::1000 Credited Success Fully > pool-1-thread-3 :: Jerry says :: now balance is 6800 > pool-1-thread-3 :: Tom says :: now balance is 23200 > pool-1-thread-3 says :: Transfer successfully > > ***A ReentrantLock is owned by the thread last successfully locking, but not yet unlocking it. A thread invoking lock will return, successfully acquiring the lock, when the lock is not owned by another thread. The method will return immediately if the current thread already owns the lock. This can be checked using methods isHeldByCurrentThread(), and getHoldCount().*** > > ***The constructor for this class accepts an optional fairness parameter. When set true, under contention, locks favor granting access to the longest-waiting thread. Otherwise this lock does not guarantee any particular access order. Programs using fair locks accessed by many threads may display lower overall throughput (i.e., are slower; often much slower) than those using the default setting, but have smaller variances in times to obtain locks and guarantee lack of starvation. Note however, that fairness of locks does not guarantee fairness of thread scheduling. Thus, one of many threads using a fair lock may obtain it multiple times in succession while other active threads are not progressing and not currently holding the lock. Also note that the untimed tryLock() method does not honor the fairness setting. It will succeed if the lock is available even if other threads are waiting.*** [https://dzone.com/articles/java-concurrency-reentrant-lock-1][https_dzone.com_articles_java-concurrency-reentrant-lock-1] [https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReentrantLock.html][https_docs.oracle.com_javase_8_docs_api_java_util_concurrent_locks_ReentrantLock.html] [SouthEast]: /images/20220602/2fc7dca6ee9142c49136c70d82dc4fc6.png [SouthEast 1]: /images/20220602/0a29d9f9cac14bfb8db5b6d01e28470c.png [https_dzone.com_articles_java-concurrency-reentrant-lock-1]: https://dzone.com/articles/java-concurrency-reentrant-lock-1 [https_docs.oracle.com_javase_8_docs_api_java_util_concurrent_locks_ReentrantLock.html]: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReentrantLock.html
还没有评论,来说两句吧...