重入锁
为什么叫重入锁?是因为同一个线程可以重复进入自己获取的锁.
1.重入锁的特性
1.1重入锁比synchronized更灵活,它能够显式指定何时加锁,何时解锁.(实例方法lock(),unlock())
1.2中断响应
使用ReentrantLock的实例方法lockInterruptibly()方法(建议使用可以响应中断的锁),可以在线程要求中断的时候进行响应,避免死锁情况下一直等待.
public class ReentrantLockInterruptDemo implements Runnable { public static ReentrantLock lock1 = new ReentrantLock(); public static ReentrantLock lock2 = new ReentrantLock(); int i; public ReentrantLockInterruptDemo(int i){ this.i = i; } @Override public void run() { // TODO Auto-generated method stub try { if(i==1){ //对锁的请求,统一使用lockInterruptibly方法,这是一个可以对中断进行响应的锁申请动作.在等待锁的时候可以响应中断 lock1.lockInterruptibly(); try { Thread.sleep(500); } catch (Exception e) { // TODO: handle exception } lock2.lockInterruptibly(); }else{ //对锁的请求,统一使用lockInterruptibly方法,这是一个可以对中断进行响应的锁申请动作.在等待锁的时候可以响应中断 lock2.lockInterruptibly(); try { Thread.sleep(500); } catch (Exception e) { // TODO: handle exception } lock1.lockInterruptibly(); } } catch (InterruptedException e) { // TODO: handle exception e.printStackTrace(); }finally{ if(lock1.isHeldByCurrentThread()){ lock1.unlock(); }else if(lock2.isHeldByCurrentThread()){ lock2.unlock(); } System.out.println(Thread.currentThread().getId()+":线程退出"); } } /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { // TODO Auto-generated method stub Thread t1 = new Thread(new ReentrantLockInterruptDemo(1)); Thread t2 = new Thread(new ReentrantLockInterruptDemo(2)); t1.start(); t2.start(); Thread.sleep(2000); t2.interrupt(); } }
1.3锁申请等待限时
申请锁的时候(使用tryLock(timeout, unit)方法),可以指定等待时间,如果在指定时间内没有获取到锁,返回false,否则返回true;而无参的tryLock()方法,当前线程会去尝试获得锁,如果锁被其他线程占用,则立即返回false,不会引起线程等待.
public class ReentrantLockTryLockDemo implements Runnable { public static ReentrantLock lock = new ReentrantLock(); @Override public void run() { try { System.out.println("我进来了,我要获取锁,我是_"+Thread.currentThread().getName()); if(lock.tryLock(5, TimeUnit.SECONDS)){ System.out.println("谁进来了?我是_"+Thread.currentThread().getName()); Thread.sleep(6000); }else{ System.out.println("没获取到锁,我走了_"+Thread.currentThread().getName()); } } catch (Exception e) { e.printStackTrace(); }finally{ if(lock.isHeldByCurrentThread()){ lock.unlock(); } } } /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { ReentrantLockTryLockDemo rt = new ReentrantLockTryLockDemo(); Thread t1 = new Thread(rt); Thread t2 = new Thread(rt); t1.start(); t2.start(); } }
1.4公平锁设置
重入锁可以对锁的公平性进行设置.在ReentrantLock的构造函数中.公平锁需要维护一个队列(按照线程的进入顺序,不论优先级高低).
但是由于实现成本较高,性能比较低,因此默认情况下是非公平的.
public class ReentrantLockFairDemo implements Runnable { //设置公平锁 public static ReentrantLock fairLock = new ReentrantLock(true); @Override public void run() { while(true){ try { fairLock.lock(); System.out.println("我是_"+Thread.currentThread().getName()); } catch (Exception e) { e.printStackTrace(); }finally{ fairLock.unlock(); } } } /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { ReentrantLockFairDemo rt = new ReentrantLockFairDemo(); Thread t1 = new Thread(rt,"Thread_t1"); Thread t2 = new Thread(rt,"Thread_t2"); t1.start(); t2.start(); }
1.5重入锁的好伙伴:Condition条件对象
在synchronized中,我们可以使用Object对象提供的wait()和notify()方法实现线程的挂起和唤醒(线程Thread中的suspend和resume已经废弃).
换句话说,Object对象中的wait()和notify()方法是和synchronized合用起来完成线程的挂起和唤醒操作的.
在重入锁中,我们使用Condition条件对象与重入锁合用,来实现线程的挂起(await)与唤醒(singal).
在使用时,我们需要使用ReentrantLock中的实例方法newCondition()得到Condition对象,将重入锁与对应的Condition对象进行绑定,实现线程的等待与唤醒.
具体方法介绍如下:
await()方法:与Object类中的wait()方法类似,在Condition接口中,提供了方法await(),调用后使当前线程等待,同时释放当前锁.在等待过程中可以响应中断.
awaitUninterruptibly()方法:功能与await()一样,不同的是,在等待过程中不响应中断.
singal()方法:用于唤醒一个在等待队列中的线程.
singalAll()方法:用于唤醒所有在等待队列中的线程.
public class ReentrantLockCondition implements Runnable{ public static ReentrantLock lock = new ReentrantLock(); public static Condition condition = lock.newCondition(); @Override public void run() { try { //加锁 lock.lock(); System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"获取锁执行等待...."); //等待,并释放锁 condition.await(); System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"开始执行任务...."); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"执行完成...."); lock.unlock(); System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"线程释放锁...."); } } /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { // TODO Auto-generated method stub Thread t1 = new Thread(new ReentrantLockCondition()); Thread t2 = new Thread(new ReentrantLockCondition()); t1.start(); t2.start(); Thread.sleep(2000); System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"线程获取锁...."); //重新获取锁 lock.lock(); //唤醒 System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"线程通知T1...."); condition.signalAll(); //释放锁 lock.unlock(); System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"释放锁...."); } }
相关推荐
在Java多线程并发编程中,ReentrantReadWriteLock(可重入读写锁)是一个重要的同步工具,它属于Java并发包(java.util.concurrent.locks)中的一个类。这个锁提供了比标准的synchronized关键字更细粒度的控制,允许...
Java中的ReentrantLock是Java并发包(java.util.concurrent.locks)中的一个高级锁,它是可重入的,意味着一个线程可以多次获取同一锁。在深入ReentrantLock之前,我们首先需要了解Java并发编程的基础,特别是Java...
它是实现Java并发包中锁和其他同步器的基础框架,例如ReentrantLock(可重入锁)、Semaphore(信号量)、CountDownLatch(倒计时门闩)、CyclicBarrier(循环栅栏)以及ReentrantReadWriteLock(可重入读写锁)等。...
LockSupport是Java中用于多线程同步的一个工具类,它提供了一组基础的线程阻塞和解除阻塞的方法。这个类位于java.util.concurrent.locks包下,是实现并发编程中AQS(AbstractQueuedSynchronizer)框架的重要基础之一...
并发库高级应用\多线程\Java
《Java多线程编程实战指南-...通过《Java多线程编程实战指南-核心篇》,你可以深入了解Java并发编程的各个方面,提升在高并发场景下的编程能力。书中的案例和练习将帮助你更好地掌握理论知识,并将其应用于实际项目中。
本文将围绕“Java多线程高并发相关资料收集”这一主题,详细探讨这两个领域的核心知识点。 首先,多线程是指在单个程序中同时执行多个线程。Java提供了一个强大的多线程支持,允许开发者创建、管理和控制多个执行...
Java多线程与并发是Java编程中至关重要的一个领域,特别是在构建高性能、高并发的应用时。线程基础是理解并发编程的关键,它涉及到线程的状态转换、创建与使用方式、同步与协作机制等方面。 线程有五种基本状态: 1...
Java 模拟线程并发是编程领域中的一个重要概念,尤其在多核处理器和高并发应用中,理解并熟练掌握线程并发技术对于提升程序性能至关重要。在Java中,线程并发可以通过多种方式实现,包括继承Thread类、实现Runnable...
Java多线程实战精讲是Java开发者必备的技能之一,特别是在处理高并发场景时,它的重要性不言而喻。本文将深入探讨Java多线程的相关知识点,帮助你全面理解并掌握这一核心概念。 1. **线程基础** - **线程定义**:...
### Java多线程与并发(15-26)-JUC集合-ConcurrentLinkedQueue详解 #### 一、ConcurrentLinkedQueue概述 `ConcurrentLinkedQueue`是Java实用工具包(J.U.C)中的一个高性能线程安全队列,主要用于解决多线程环境下...
java多线程与高并发java多线程与高并发java多线程与高并发
### Java多线程与并发(14-26)-JUC集合-CopyOnWriteArrayList详解 #### 一、概述 `CopyOnWriteArrayList`是一种线程安全的集合类,它是`ArrayList`的一种特殊版本,主要通过复制底层数组的方式来保证线程安全性。...
Java多线程与并发处理是Java编程中的高级话题,涉及到JUC(java.util.concurrent)包中的原子类、CAS(Compare-And-Swap)机制、Unsafe类以及多线程并发的无锁方案和线程安全的实现方法。 CAS是一种无锁的同步机制...
【Java 多线程与并发】并发集合类`ConcurrentHashMap`是Java程序设计中一个重要的工具,尤其在高并发场景下,它提供了高效的线程安全。`ConcurrentHashMap`在JDK 1.7和1.8中有着显著的区别。 在JDK 1.7中,`...
Java多线程与并发编程是Java语言中用于处理多任务执行的关键技术,它能够帮助开发者设计出能够有效应对高并发请求的应用程序。在现代的线上(Online)和离线(Offline)应用中,合理利用多线程技术可以大幅提高系统...
#### 一、Java多线程并发简介 在现代软件开发中,特别是在Java这样的主流编程语言中,多线程并发技术是提高程序执行效率、优化资源利用的关键手段之一。本篇文章将深入探讨Java中的多线程并发机制,并通过具体的...
张孝祥Java多线程与并发库高级应用学习笔记,很经典的学习多线程和并发的资料。张孝祥Java多线程讲义笔记由张孝祥亲自整理,很实用的。