Lock是JDK1.5种新增的同步工具,其实真正的实现Lock接口的类就三个,ReentrantLock和ReentrantReadWriteLock的两个内部类(ReadLock和WriteLock实现了Lock的接口);
ReentrantLock 实现了标准的互斥操作,也就是一次只能有一个线程持有锁,也即所谓独占锁的概念。我们也一直在强调这个特点。显然这个特点在一定程度上面减低了吞吐量,实际上独占锁是一种保守的锁策略,在这种情况下任何“读/读”,“写/读”,“写/写”操作都不能同时发生。
public class ReentrantLockTest { // 公平锁 private Lock lock = new ReentrantLock(true); // 资源 private Resource resource = new Resource(); public static void main(String[] args) { final ReentrantLockTest test = new ReentrantLockTest(); ExecutorService service = Executors.newCachedThreadPool(); for (int i = 0; i < 20; i++) { service.submit(new Runnable() { @Override public void run() { Random random = ThreadLocalRandom.current(); test.write(random.nextInt()); } }); service.submit(new Runnable() { @Override public void run() { test.read(); } }); } service.shutdown(); } private void write(final int value) { // 如果可以获取锁 if (lock.tryLock()) { try { // 执行业务逻辑 System.out.println(Thread.currentThread().getName() + "获取了锁 写入 value=" + value); resource.setValue(String.valueOf(value)); } finally { // 释放锁 System.out.println(Thread.currentThread().getName() + "释放了锁"); lock.unlock(); } } } void read() { if (lock.tryLock()) { try { System.out.println(Thread.currentThread().getName() + "获取了锁 value=" + resource.getValue()); } finally { System.out.println(Thread.currentThread().getName() + "释放了锁"); lock.unlock(); } } } }
测试的结果是:
pool-1-thread-1获取了锁 写入 value=2111184282 pool-1-thread-1释放了锁 pool-1-thread-2获取了锁 value=2111184282 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 写入 value=-1679499784 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 写入 value=1678350750 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 value=1678350750 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 value=1678350750 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 写入 value=152101866 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 value=152101866 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 写入 value=1147384711 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 value=1147384711 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 写入 value=-2130483959 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 value=-2130483959 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 写入 value=417404714 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 value=417404714 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 写入 value=-405288963 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 value=-405288963 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 写入 value=-139338780 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 value=-139338780 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 写入 value=-745627488 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 value=-745627488 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 写入 value=-1455461843 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 value=-1455461843 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 写入 value=-1129478741 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 写入 value=-1560021948 pool-1-thread-2释放了锁
但实际应用场景中我们会经常遇到这样的情况:某些资源需要并发访问,并且大部分时间是用来进行读操作的,写操作比较少,而锁是有一定的开销的,当并发比较大 的时候,锁的开销就比较可观了。所以如果可能的话就尽量少用锁,如果非要用锁的话就尝试看能否能实现读写分离,将其改造为读写锁。
// 公平锁 private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); // 写锁 private Lock writeLock = readWriteLock.writeLock(); // 读锁 private Lock readLock = readWriteLock.readLock(); // 资源 private Resource resource = new Resource(); public static void main(String[] args) { final ReentrantReadWriteLockTest test = new ReentrantReadWriteLockTest(); ExecutorService service = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { service.submit(new Runnable() { @Override public void run() { Random random = ThreadLocalRandom.current(); test.write(random.nextInt()); } }); service.submit(new Runnable() { @Override public void run() { test.read(); } }); } service.shutdown(); } private void write(final int value) { // 如果可以获取锁 if (writeLock.tryLock()) { try { // 执行业务逻辑 System.out.println(Thread.currentThread().getName() + "获取了锁 写入 value=" + value); resource.setValue(String.valueOf(value)); } finally { // 释放锁 System.out.println(Thread.currentThread().getName() + "释放了锁"); writeLock.unlock(); } } } private void read() { if (readLock.tryLock()) { try { System.out.println(Thread.currentThread().getName() + "获取了锁 value=" + resource.getValue()); } finally { System.out.println(Thread.currentThread().getName() + "释放了锁"); readLock.unlock(); } } } }
测试结果是:
pool-1-thread-1获取了锁 写入 value=-702575113 pool-1-thread-1释放了锁 pool-1-thread-1获取了锁 value=-702575113 pool-1-thread-1释放了锁 pool-1-thread-1获取了锁 写入 value=-1619148924 pool-1-thread-1释放了锁 pool-1-thread-1获取了锁 value=-1619148924 pool-1-thread-1释放了锁 pool-1-thread-1获取了锁 写入 value=-1469315956 pool-1-thread-1释放了锁 pool-1-thread-1获取了锁 value=-1469315956 pool-1-thread-1释放了锁 pool-1-thread-1获取了锁 写入 value=1667915800 pool-1-thread-1释放了锁 pool-1-thread-1获取了锁 value=1667915800 pool-1-thread-1释放了锁 pool-1-thread-1获取了锁 写入 value=-1280947014 pool-1-thread-1释放了锁 pool-1-thread-1获取了锁 value=-1280947014 pool-1-thread-1释放了锁 pool-1-thread-1获取了锁 写入 value=1208950056 pool-1-thread-1释放了锁 pool-1-thread-1获取了锁 value=1208950056 pool-1-thread-1释放了锁 pool-1-thread-1获取了锁 写入 value=1089508899 pool-1-thread-1释放了锁 pool-1-thread-1获取了锁 写入 value=760397757 pool-1-thread-1释放了锁 pool-1-thread-2获取了锁 value=760397757 pool-1-thread-2释放了锁 pool-1-thread-2获取了锁 value=760397757 pool-1-thread-1获取了锁 value=760397757 pool-1-thread-2释放了锁 pool-1-thread-1释放了锁
可以发现写锁是独占锁,读锁是共享锁,那么读锁是不是无限共享呢?实际上不是的,最大同时可以背65534个共享。
public class ReentrantTest { private Lock lock = new ReentrantReadWriteLock().readLock(); static long count = 0; /** * * @param args * @author zhangwei<wei.zw@corp.netease.com> */ public static void main(String[] args) { ReentrantTest test = new ReentrantTest(); for (;;) { if (test.lock.tryLock()) { System.out.println(count++); } } } }
65530 65531 65532 65533 65534 Exception in thread "main" java.lang.Error: Maximum lock count exceeded at java.util.concurrent.locks.ReentrantReadWriteLock$Sync.tryReadLock(ReentrantReadWriteLock.java:588) at java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock.tryLock(ReentrantReadWriteLock.java:803) at org.demo.core.lock.ReentrantTest.main(ReentrantTest.java:34)
锁降级 写线程获取写入锁后可以获取读取锁,然后释放写入锁,这样就从写入锁变成了读取锁,从而实现锁降级的特性。
public class DegradeReentrantReadWriteLockTest2 { // 公平锁 private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); // 写锁 private Lock writeLock = readWriteLock.writeLock(); // 读锁 private Lock readLock = readWriteLock.readLock(); // 资源 private Resource resource = new Resource(); public static void main(String[] args) { final DegradeReentrantReadWriteLockTest2 test = new DegradeReentrantReadWriteLockTest2(); ExecutorService service = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { service.submit(new Runnable() { @Override public void run() { Random random = ThreadLocalRandom.current(); test.writeAndRead(random.nextInt()); } }); service.submit(new Runnable() { @Override public void run() { test.read(); } }); } service.shutdown(); } private void writeAndRead(final int value) { // 如果可以获取锁 try { try { // 写锁锁定 writeLock.lock(); // 执行业务逻辑 System.out.println(Thread.currentThread().getName() + "获取了写锁 写入 value=" + value); resource.setValue(String.valueOf(value)); } finally { System.out.println(Thread.currentThread().getName() + "写锁降级为读锁"); // 读锁锁定 readLock.lock(); // 释放写锁 writeLock.unlock(); } System.out.println(resource.getValue()); } finally { // 释放读锁 System.out.println(Thread.currentThread().getName() + "释放了读锁"); readLock.unlock(); } } private void read() { if (readLock.tryLock()) { try { System.out.println(Thread.currentThread().getName() + "获取了读锁 value=" + resource.getValue()); } finally { System.out.println(Thread.currentThread().getName() + "释放了读锁"); readLock.unlock(); } } } }
公平锁的实现:公平性是指最先试图获取锁的线程一定可以保证最先获取
如果当前线程之前还有线程在等待,获取锁失败!通过队列排序保证获取锁的公平性。
/** * Sync object for fair locks */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { acquire(1); } /** * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. */ protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } }
相关推荐
Java多线程编程是提升程序性能和响应性的关键技术。理解多线程的概念,掌握线程的创建、同步、通信、死锁避免等核心知识点,以及合理使用线程池,对于编写高效、稳定的并发程序至关重要。通过实践,开发者可以更好地...
(注意,本资源附带书中源代码可供参考) 多线程与并发处理是程序设计好坏优劣的重要课题,本书通过浅显易懂的文字与实例来介绍Java线程相关的设计模式概念,并且通过实际的Java程序范例和 UML图示来一一解说,书中...
Java的多线程机制是Java语言的一大特性,它允许程序同时执行多个任务,提升程序响应速度,优化资源利用率。在Java中,线程是程序执行的最小单位,一个进程可以包含多个线程,每个线程都有自己独立的生命周期,包括...
### Java多线程详解:深度探索Java线程机制 #### 知识点一:线程与进程的区别 在深入探讨Java多线程之前,我们首先需要理解线程与进程的基本概念及其区别。进程是资源分配的基本单位,拥有独立的内存空间,而线程...
Java多线程是Java编程中的重要概念,它允许程序同时执行多个任务,从而提升系统效率和资源利用率。本文将深入探讨Java多线程机制,包括线程的创建、同步、通信以及常见设计模式。 首先,Java中创建线程主要有两种...
### Java多线程编程详解 #### 一、理解多线程机制 多线程是一种让程序能够并发执行多个指令流的机制,每一个这样的指令流被称为一个线程,它们彼此独立运行。线程与进程相似之处在于都有独立的执行控制,但不同的...
总之,《Java多线程编程详解》这份PDF文档全面覆盖了Java多线程编程的核心内容,无论你是初学者还是有经验的开发者,都能从中受益。通过学习,你可以更好地理解和掌握如何在Java中有效地利用多线程,提升程序的性能...
Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,提升程序的效率和响应性。本文将详细解析Java中实现多线程的两种主要方式,并讨论线程的基本概念和内存模型。 首先,理解多线程的概念至关...
【JAVA基础】JAVA多线程编程详解 Java多线程编程是Java开发中不可或缺的一部分,它允许多个任务在同一时间并发执行,提高了程序的效率和响应性。在Java中,线程是程序中的执行流,每个线程都有独立的执行控制,由...
《Java多线程编程实战指南》这本书深入浅出地讲解了Java多线程的核心概念和实战技巧,分为核心篇和设计模式篇,旨在帮助开发者掌握并应用多线程技术。 1. **线程基础** - **线程的创建**:Java提供了两种创建线程...
Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,实现多线程有两种主要方式:通过继承`Thread`类或者实现`Runnable`接口。 1. **继承Thread类*...
### Java多线程编程详解:深入探讨synchronized与并发机制 在Java的多线程编程领域,`synchronized`关键字及其引发的并发控制问题尤为重要。本文将基于标题、描述、标签以及部分内容,深入剖析Java多线程编程的核心...
JAVA多线程练习题答案详解 在本文中,我们将对 JAVA 多线程练习题的答案进行详细的解释和分析。这些题目涵盖了 JAVA 多线程编程的基本概念和技术,包括线程的生命周期、线程同步、线程状态、线程优先级、线程安全等...
Java多线程设计模式是...通过阅读“java多线程设计模式详解(PDF及源码)”的资料,我们可以深入了解这些知识点,并通过提供的源码加深理解,学习如何在实际项目中应用多线程设计模式,提高程序的并发性能和可维护性。
Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,多线程的实现...通过阅读《Java多线程编程详解.pdf》这样的资料,可以系统学习和掌握这些知识。
Java多线程编程深入详解 多线程编程是Java编程语言中的一种重要技术,用于提高程序的执行效率和响应速度。在本文中,我们将深入探讨Java多线程编程的基础知识和高级技术。 什么是多进程和多线程? 在计算机科学中...
Java多线程模式详解 目录: 一、漫谈UML Java语言的线程 多线程的评量标准 二、 1、Single Threaded Execution ———— 能通过这座桥的,只有一个人 2、Immutable ———— 想破坏它也没办法 3、Guarded ...