Java并发编程:Lock
一.Lock
实现提供了比使用 synchronized 方法和语句更灵活、更具可伸缩性的锁定机制,可以支持多个相关的 Condition 对象。
Lock&synchronized用途比较
基本语法上,ReentrantLock与synchronized很相似,它们都具备一样的线程重入特性,只是代码写法上有点区别而已,一个表现为API层面的互斥锁(Lock),一个表现为原生语法层面的互斥锁(synchronized)。ReentrantLock相对synchronized而言还是增加了一些高级功能,主要有以下三项:
1.等待可中断:当持有锁的线程长期不释放锁时,正在等待的线程可以选择放弃等待,改为处理其他事情,它对处理执行时间非常上的同步块很有帮助。而在等待由synchronized产生的互斥锁时,会一直阻塞,是不能被中断的。
2.可实现公平锁:多个线程在等待同一个锁时,必须按照申请锁的时间顺序排队等待,而非公平锁则不保证这点,在锁释放时,任何一个等待锁的线程都有机会获得锁。synchronized中的锁时非公平锁,ReentrantLock默认情况下也是非公平锁,但可以通过构造方法ReentrantLock(ture)来要求使用公平锁。
3.锁可以绑定多个条件:ReentrantLock对象可以同时绑定多个Condition对象(条件变量或条件队列),而在synchronized中,锁对象的wait()和notify()或notifyAll()方法可以实现一个隐含条件,但如果要和多于一个的条件关联的时候,就不得不额外地添加一个锁,而ReentrantLock则无需这么做,只需要多次调用newCondition()方法即可。而且我们还可以通过绑定Condition对象来判断当前线程通知的是哪些线程(即与Condition对象绑定在一起的其他线程)。
实现类:ReentrantLock(可重入互斥锁)、 ReentrantReadWriteLock.ReadLock、 ReentrantReadWriteLock.WriteLock
Lock的简单的使用:
Lock lock = new ReentrantLock();//默认使用非公平锁,如果要使用公平锁,需要传入参数true lock.lock(); try { //To doSomething } catch(Exception e){ } finally { //一定在finally块中释放锁,如果锁中的代码将抛出异常,锁就有可能永远得不到释放。 lock.unlock(); }
二.Lock&Condition(执行条件)
Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法
常用方法:await()和signal()方法
例子:用Lock Condition改写上一个程序程序:子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次。
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ConditionCommunication { public static void main(String[] args) { final Business bussiness = new Business(); new Thread(new Runnable() { public void run() { for (int i = 1; i <= 50; i++) { bussiness.sub(i); } } }).start(); for (int i = 1; i <= 50; i++) { bussiness.main(i); } } static class Business { Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); private boolean bShouldSub = true; public void sub(int i) { lock.lock(); try { while (!bShouldSub) { // 防止虚假唤醒 try { condition.await(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } for (int j = 1; j <= 10; j++) { System.out.println("sub thread sequence of " + j + ", loop of " + i); } bShouldSub = false; condition.signal(); } finally { lock.unlock(); } } public void main(int i) { lock.lock(); try { while (bShouldSub) { try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int j = 1; j <= 100; j++) { System.out.println("main thread sequence of " + j + ", loop of " + i); } bShouldSub = true; condition.signal(); } finally { lock.unlock(); } } } }
可以参照Condition的Api中有个阻塞队列的实例
需要注意Condition中的是await()方法, 不是从Object继承的wait() (用错不报错)。
另一个例子:
/* 主线程循环100,子线程1循环10次,子线程2循环20次 接着又回到主线程循环100次,接着再回到子线程1.....,如此循环50次,请写出程序。 */ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ThreeConditionCommunication { public static void main(String[] args) { final Business bussiness = new Business(); new Thread(new Runnable() { public void run() { for (int i = 1; i <= 50; i++) { bussiness.sub2(i); } } }).start(); new Thread(new Runnable() { public void run() { for (int i = 1; i <= 50; i++) { bussiness.sub3(i); } } }).start(); for (int i = 1; i <= 50; i++) { bussiness.main(i); } } static class Business { Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); private int ShouldSub = 1; public void sub2(int i) { lock.lock(); try{ while (ShouldSub != 2) { //防止虚假唤醒 try { condition2.await(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } for (int j = 1; j <= 10; j++) { System.out.println("sub2 thread sequence of " + j + ", loop of " + i); } ShouldSub = 3; condition3.signal(); }finally { lock.unlock(); } } public void sub3(int i) { lock.lock(); try{ while (ShouldSub != 3) { //防止虚假唤醒 try { condition3.await(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } for (int j = 1; j <= 20; j++) { System.out.println("sub3 thread sequence of " + j + ", loop of " + i); } ShouldSub = 1; condition1.signal(); }finally { lock.unlock(); } } public void main(int i) { lock.lock(); try{ while (ShouldSub != 1) { try{ condition1.await(); } catch(InterruptedException e) { e.printStackTrace(); } } for (int j = 1; j <= 100; j++) { System.out.println("main thread sequence of " + j + ", loop of "+ i); } ShouldSub = 2; condition2.signal(); }finally{ lock.unlock(); } } } }
三.读写锁
读写锁将对一个资源(比如文件)的访问分成了2个锁,一个读锁和一个写锁。
正因为有了读写锁,才使得多个线程之间的读操作不会发生冲突。
ReadWriteLock就是读写锁,它是一个接口,ReentrantReadWriteLock实现了这个接口。
可以通过readLock()获取读锁,通过writeLock()获取写锁。
例子:读写锁,创建3个线程用来读 , 3个线程用来写
import java.util.Random; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteLockTest { public static void main(String[] args) { final Queue que = new Queue(); for (int i = 0; i < 3; i++) { new Thread(new Runnable() { public void run() { while (true) { que.get(); } } }).start(); new Thread(new Runnable() { public void run() { while (true) { que.put(new Random().nextInt(10000)); } } }).start(); } } } class Queue { private Object data = null; // 需要读写的对象 ReadWriteLock rwl = new ReentrantReadWriteLock(); public void get() { rwl.readLock().lock(); try { System.out.println(Thread.currentThread().getName() + " is ready to get data!"); Thread.sleep(new Random().nextInt(1000)); System.out.println(Thread.currentThread().getName() + " hava read data: " + data); } catch (InterruptedException e) { e.printStackTrace(); } finally { rwl.readLock().unlock(); } } public void put(Object data) { rwl.writeLock().lock(); try { System.out.println(Thread.currentThread().getName() + " is ready to put data!"); Thread.sleep((long) Math.random() * 1000); this.data = data; System.out.println(Thread.currentThread().getName() + " have write data " + data); } catch (InterruptedException e) { e.printStackTrace(); } finally { rwl.writeLock().unlock(); } } }
总结来说,Lock和synchronized有以下几点不同:
1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;
2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
5)Lock可以提高多个线程进行读操作的效率。
当需要以下高级特性时,才应该使用:可定时的、可轮询的与可中断的锁获取操作,公平队列,或者非块结构的锁。否则,请使用synchronized。
相关推荐
本文的主题是关于具有java语言风格的Thread、synchronized、volatile,以及J2SE5中新增的概念,如锁(Lock)、原子性(Atomics)、并发集合类、线程协作摘要、Executors。开发者通过这些基础的接口可以构建高并发、线程...
《Java并发编程的艺术》笔记 第一章 并发编程的挑战 第二章 Java并发机制的底层实现原理 volatile的两条实现原则: 1. Lock前缀指令会引起处理器缓存回写到内存 2. 一个处理器的缓存回写到内存会导致其他...
龙果 java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四...
07-JUC高并发编程-Lock接口概述和实现案例.mp48 G J/ u; W' _$ o: {2 M 08-JUC高并发编程-线程间通信-概述和案例分析.mp4 09-JUC高并发编程-线程间通信-Synchronized实现案例.mp4 10-JUC高并发编程-线程间通信-虚假...
Lock接口认识与使用.mp4 手动实现一个可重入锁.mp4 AbstractQueuedSynchronizer(AQS)详解.mp4 使用AQS重写自己的锁.mp4 重入锁原理与演示.mp4 读写锁认识与原理.mp4 细读ReentrantReadWriteLock源码.mp4 ...
Java并发编程(20)并发新特性—Lock锁和条件变量(含代码)编程开发技术共14页.pdf.zip
第20节Lock接口认识与使用00:19:54分钟 | 第21节手动实现一个可重入锁00:26:31分钟 | 第22节AbstractQueuedSynchronizer(AQS)详解00:49:04分钟 | 第23节使用AQS重写自己的锁00:31:04分钟 | 第24节重入锁原理与...
Java 并发学习笔记: 进程和线程, 并发理论, 并发关键字, Lock 体系, 原子操作类, 发容器 & 并发工具, 线程池, 并发实践 Java是一种面向对象的编程语言,由Sun Microsystems于1995年推出。它是一种跨平台的...
java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个...
java并发编程 基础知识,守护线程与线程, 并行和并发有什么区别? 什么是上下文切换? 线程和进程区别 什么是线程和进程? 创建线程有哪几种方式?,如何避免线程死锁 线程的 run()和 start()有什么区别? 什么是 ...
并发编程:编写多线程代码,解决多线程带来的问题 为什么要学并发编程? 首先,来看一个案例:手写网站服务器案例。 高性能应用程序的一把钥匙,应用程序的翅膀,面试高频的考点 中间件几乎都是多线程应用:MySQL、...
java7在并发编程方面,带来了很多令人激动的新功能,这将使你的应用程序具备更好的并行任务性能。 《Java 7并发编程实战手册》是Java 7并发编程的实战指南,介绍了Java 7并发API中大部分重要而有用的机制。全书分为9...
java 并发 编程 多线程 concurrent lock condition executorserice executor java.util.curcurrent.
│ Java并发编程.png │ ppt+源码.rar │ 高并发编程第二阶段01讲、课程大纲及主要内容介绍.wmv │ 高并发编程第二阶段02讲、介绍四种Singleton方式的优缺点在多线程情况下.wmv │ 高并发编程第二阶段03讲、...
Java并发编程实战 本书深入浅出地介绍了Java线程和并发,是一本完美的Java并发参考手册。书中从并发性和线程安全性的基本概念出发,介绍了如何使用类库提供的基本并发构建块,用于避免并发危险、构造线程安全的类及...
Java并发编程常见问题说明,包括Lock,synchronized,volatile等
主要介绍了浅谈Java并发编程之Lock锁和条件变量,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
接着,深入讲解了Java并发编程的核心API,如synchronized关键字、Lock接口、Condition接口、Semaphore等,帮助读者掌握Java并发编程的基本工具和方法。 除了基础知识和API的讲解,本书还重点介绍了Java并发编程的...
2万字Java并发编程面试题合集(含答案,建议收藏) 具体如下 1、在 java 中守护线程和本地线程区别?2、线程与进程的区别?3、什么是多线程中的上下文切换?4、死锁与活锁的区别,死锁与饥饿的区别?5、Java 中用到...