在之前的多线程编程的文章中我们讲到了如何使用关键字synchronized加锁来实现同步访问。本文我们继续来探讨锁这个问题,从Java 5之后,在java.util.concurrent.locks包下提供了另外一种锁的方式来实现同步访问,那就是Lock。
既然都可以通过synchronized锁来实现同步访问了,那么为什么Java还提供java.util.concurrent.locks包来实现锁的机制? 即生瑜,何生亮?
这里就不得不罗列一下synchronized的不足之处:使用synchronized关键字会锁住某一段程序,别的程序如果需要调用的话就必须等待,这样减少了速度、效率。并发的情况下有可能产生死锁,导致程序中断。而且对多线程环境中,使用synchronized后,线程要么获得锁,执行相应的代码,要么无法获得锁处于等待状态,对于锁的处理不灵活。而Lock提供了多种基于锁的处理机制,比如:
- lockInterruptibly() 如果当前线程未被中断,则获取锁。
- tryLock() 仅在调用时锁为空闲状态才获取该锁。
- unlock() 释放锁。
多线程竞争一个锁(synchronized锁)时,其余未得到锁的线程只能不停的尝试获得锁,而不能中断。高并发的情况下会导致性能下降。ReentrantLock的 lockInterruptibly()方法可以优先考虑响应中断。 一个线程等待时间过长,它可以中断自己,然后ReentrantLock响应这个中断,不再让这个线程继续等待。有了这个机制,使用 ReentrantLock时就不会像synchronized那样产生死锁了。
一:关于java.util.concurrent.locks包
查看JDK源码,先了解一下locks包下都有哪些class文件,大致熟悉下包里文件的个数、文件名
查看包文件后,接下来就要查看每一个文件,进行分类,哪些class文件是interface类型,哪些是class类型,以及接口与实现类之间的对应关系。
整理包下的类关系图为:
说明:
- 其中类ReadLock和WriteLock的代码是位于ReentrantReadWriteLock.java文件里,且有加public static关键字进行修饰。
- 其中类ReentrantLock.java的文件里还含有:Sync、NonfairSync、FairSync三个静态类。其中Sync extends AbstractQueuedSynchronizer
二:Lock源码
package java.util.concurrent.locks; import java.util.concurrent.TimeUnit; /** * {@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. */ public interface Lock { /** * Acquires the lock. */ void lock(); /** * Acquires the lock unless the current thread is * {@linkplain Thread#interrupt interrupted}. */ void lockInterruptibly() throws InterruptedException; /** * Acquires the lock only if it is free at the time of invocation. */ boolean tryLock(); /** * Acquires the lock if it is free within the given waiting time and the * current thread has not been {@linkplain Thread#interrupt interrupted}. */ boolean tryLock(long time, TimeUnit unit) throws InterruptedException; /** * Releases the lock. */ void unlock(); /** * Returns a new {@link Condition} instance that is bound to this * {@code Lock} instance. * */ Condition newCondition(); }
说明:
-
lock()、tryLock()、tryLock(long time, TimeUnit unit)和lockInterruptibly()是用来获取锁的。
- unLock()方法是用来释放锁的。
- newCondition()用于线程协作。
三:Lock的使用
用一个简单的例子来看看Lock是怎么用的
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.lang.math.RandomUtils; public class LockDemo { Lock lock = new ReentrantLock(); public static void main(String[] args){ final LockDemo d = new LockDemo(); new Thread(){ @Override public void run(){ d.insert(Thread.currentThread()); } }.start(); new Thread(){ @Override public void run(){ d.insert(Thread.currentThread()); } }.start(); } public void insert(Thread thread){ //加锁 lock.lock(); try{ System.out.println(thread.getName()+"获得了锁"); // TODO 做些事情吧... Thread.sleep(RandomUtils.nextInt(100)); }catch(Exception e){ e.printStackTrace(); }finally{ //释放锁 lock.unlock(); System.out.println(thread.getName()+"释放了锁"); } } }
运行结果:
Thread-0获得了锁
Thread-0释放了锁
Thread-1获得了锁
Thread-1释放了锁
说明:申请锁是通过Lock lock = new ReentrantLock();语句实现的。在数据同步代码块里,先通过lock.lock();语句进行加锁,在退出数据同步代码块时通过lock.unlock();释放锁。需要注意的是lock.unlock()是放在finally语句里的,即这个语句的执行很重要!
参考资料:
https://www.ibm.com/developerworks/cn/java/j-jtp10264/
http://www.cnblogs.com/dolphin0520/p/3923167.html
http://blog.csdn.net/aesop_wubo/article/details/7544148
http://www.blogjava.net/BucketLi/archive/2010/09/30/333471.html
http://blog.csdn.net/chy996633/article/details/8627903
相关推荐
### Java并发编程实践知识点详解 #### 一、Java并发编程基础 ##### 1.1 并发与并行概念区分 在Java并发编程实践中,首先需要理解“并发”与“并行”的区别。“并发”指的是多个任务同时进行,但实际上可能是在多...
│ Java并发编程.png │ ppt+源码.rar │ 高并发编程第二阶段01讲、课程大纲及主要内容介绍.wmv │ 高并发编程第二阶段02讲、介绍四种Singleton方式的优缺点在多线程情况下.wmv │ 高并发编程第二阶段03讲、...
《Java高并发程序设计》是一本深入探讨Java平台上的并发编程技术的专业书籍,由葛一鸣等人编著。这本书旨在帮助读者理解并掌握在高并发环境下编写高效、稳定且可扩展的Java应用程序的关键技巧和最佳实践。以下是该书...
龙果 java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四...
并发工具类CountDownLatch详解.mp4 并发工具类CyclicBarrier 详解.mp4 并发工具类Semaphore详解.mp4 并发工具类Exchanger详解.mp4 CountDownLatch,CyclicBarrier,Semaphore源码解析.mp4 提前完成任务之FutureTask...
《Nginx高性能Web服务器详解》可能是与Java并发编程实战相关的补充阅读,因为Nginx作为一个高性能的反向代理服务器,经常与Java应用服务器配合使用,优化Web服务的并发处理能力。Nginx的异步非阻塞I/O模型和事件驱动...
为了更好地理解Java并发编程的实际应用,我们可以考虑一个简单的例子——使用`Future`和`Callable`来实现异步任务的执行。假设有一个复杂的计算任务需要长时间执行,但主程序不能等待这个任务完成。此时,可以将计算...
根据提供的信息,我们可以深入探讨Java高并发编程的相关知识点。高并发是现代软件系统设计中一个非常重要的方面,尤其是在云计算和大数据处理领域。下面将详细解释Java高并发编程的基础概念、核心技术以及实现技巧。...
第37节并发工具类CountDownLatch详解00:22:04分钟 | 第38节并发工具类CyclicBarrier 详解00:11:52分钟 | 第39节并发工具类Semaphore详解00:17:27分钟 | 第40节并发工具类Exchanger详解00:13:47分钟 | 第41节...
java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个...
根据提供的文件信息,“JAVA并发编程中文完全版”这本书旨在为读者提供全面且深入的Java并发编程知识。下面将从以下几个方面来阐述此书所涵盖的关键知识点: ### 一、Java并发编程基础 #### 1.1 Java并发模型概述 ...
- **Java并发API**: - **`java.util.concurrent`包**:提供了一系列高级并发工具类,如`ExecutorService`、`Future`、`Semaphore`等。 - **`Thread`类与`Runnable`接口**:创建线程的基本方式。 - **`Callable`...
本篇将基于书中的内容,结合并发编程的核心概念,为你详解Java并发编程的相关知识点。 首先,我们要了解什么是并发。并发是指多个任务在一段时间内交替执行,而不是一个接一个地顺序执行。在Java中,通过线程来实现...
│ Java并发编程.png │ ppt+源码.rar │ 高并发编程第二阶段01讲、课程大纲及主要内容介绍.wmv │ 高并发编程第二阶段02讲、介绍四种Singleton方式的优缺点在多线程情况下.wmv │ 高并发编程第二阶段03讲、...
Java 并发编程详解 Java 并发编程是一种编程技术,旨在充分利用多核 CPU 的计算能力,提高程序的执行效率和响应速度。在 Java 中,多线程编程是并发编程的基础,通过创建多个线程来执行不同的任务,以提高 CPU 的...
### Java并发编程实践-电子书-07章:显示锁详解 #### 一、章节概述 本章节聚焦于Java中的显示锁(Explicit Locks),尤其是`ReentrantLock`的使用和高级特性。显示锁提供了比Java自带的`synchronized`关键字更为...