Java基础教程:多线程基础(4)——Lock的使用
Java基础教程:多线程基础——锁机制
显示锁
ReentrantLock
ReentrantLock是一种标准的互斥锁,每次只允许一个线程持有ReentrantLock。
使用ReentrantLock来保护对象状态:
- Lock lock = new ReentrantLock();
- lock.lock();
- try {
- //更新对象状态
- //捕获异常,并在必要时恢复不变性条件
- }finally {
- lock.unlock();
- }
如果没有finally来释放Lock,相当于启动了一个定时炸弹。
ReentrantReadWriteLock
互斥锁是一种保守的枷锁策略,它虽然避免了“写/写”冲突,“写/读”冲突,但是同样也避免了“读/读”操作。在许多情况下,数据结构上的操作都是“读操作”。若放宽加锁需求,允许多个执行读操作的线程同时访问数据结构,那么将提高程序的性能。
我们引入读写锁,它允许一个资源可以被多个读操作访问,或者被一个写操作访问,但两者不能同时进行。也就是说当写操作进行时,所有读操作都进入阻塞状态,只有写操作完成后,读操作才能获取到最新状态,避免了脏读的发生。
在如下的代码中,我们使用读写锁封装一个Map,来使其线程安全。
- public class ReadWriteMap<K,V> {
- private final Map<K,V> map;
- private final ReadWriteLock lock = new ReentrantReadWriteLock();
- private final Lock r = lock.readLock();
- private final Lock w = lock.writeLock();
- public ReadWriteMap(Map<K,V> map){
- this.map = map;
- }
- public V put(K key,V value){
- w.lock();
- try {
- return map.put(key,value);
- } finally {
- w.unlock();
- }
- }
- public V get(Object key){
- r.lock();
- try {
- return map.get(key);
- } finally {
- r.unlock();
- }
- }
- }
使用Condition实现等待/通知
关键字Synchronized与wait、notify/All方法相结合可以实现等待/通知模式,类ReentrantLock同样可以实现相同的功能,但是需要借助Condition。
Condition类是JDK5出现的新技术,可以实现 多路通知的功能,也就是在一个Lock对象里可以创建多个Condition(即对象监视器)实例,线程对象可以注册在指定的Condition中,从而可以有选择性地进行线程通知,在调度线程上更加灵活。
必须在Condition.await()方法调用之前调用Lock.lock()方法获得同步监视器。
MyService类
- public class MyService {
- private Lock lock = new ReentrantLock();
- public Condition condition = lock.newCondition();
- public void await()
- {
- try {
- lock.lock();
- System.out.println("await的等待时间是"+System.currentTimeMillis());
- condition.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }finally {
- lock.unlock();
- }
- }
- public void signal()
- {
- try {
- lock.lock();
- System.out.println("signal的等待时间是"+System.currentTimeMillis());
- condition.signal();
- } catch (Exception e) {
- e.printStackTrace();
- }finally {
- lock.unlock();
- }
- }
- }
ThreadA类
- public class ThreadA extends Thread {
- private MyService myService;
- public ThreadA(MyService myService) {
- this.myService = myService;
- }
- @Override
- public void run() {
- myService.await();
- }
- }
Main类
- public class Main {
- public static void main(String[] args) throws InterruptedException {
- MyService myService = new MyService();
- ThreadA threadA = new ThreadA(myService);
- threadA.start();
- Thread.sleep(3000);
- myService.signal();
- }
- }
多个Condition实现通知部分线程
MyService类
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- public class MySevice {
- private Lock lock = new ReentrantLock();
- public Condition conditionA = lock.newCondition();
- public Condition conditionB = lock.newCondition();
- public void awaitA()
- {
- try {
- lock.lock();
- System.out.println("awaitA的start时间是"+System.currentTimeMillis());
- conditionA.await();
- System.out.println("awaitA的end时间是"+System.currentTimeMillis());
- } catch (InterruptedException e) {
- e.printStackTrace();
- }finally {
- lock.unlock();
- }
- }
- public void awaitB()
- {
- try {
- lock.lock();
- System.out.println("awaitB的start时间是"+System.currentTimeMillis());
- conditionB.await();
- System.out.println("awaitB的end时间是"+System.currentTimeMillis());
- } catch (InterruptedException e) {
- e.printStackTrace();
- }finally {
- lock.unlock();
- }
- }
- public void signalA()
- {
- try {
- lock.lock();
- System.out.println("signalA的等待时间是"+System.currentTimeMillis());
- conditionA.signalAll();
- } catch (Exception e) {
- e.printStackTrace();
- }finally {
- lock.unlock();
- }
- }
- public void signalB()
- {
- try {
- lock.lock();
- System.out.println("signalB的等待时间是"+System.currentTimeMillis());
- conditionB.signalAll();
- } catch (Exception e) {
- e.printStackTrace();
- }finally {
- lock.unlock();
- }
- }
- }
ThreadA类
- public class ThreadA extends Thread {
- private MySevice myService;
- public ThreadA(MySevice myService) {
- this.myService = myService;
- }
- @Override
- public void run() {
- myService.awaitA();
- }
- }
ThreadB类
- public class ThreadB extends Thread {
- private MySevice myService;
- public ThreadB(MySevice myService) {
- this.myService = myService;
- }
- @Override
- public void run() {
- myService.awaitB();
- }
- }
Main类
- public class Main {
- public static void main(String[] args) throws InterruptedException {
- MySevice mySevice =new MySevice();
- ThreadA threadA = new ThreadA(mySevice);
- ThreadB threadB = new ThreadB(mySevice);
- threadA.start();
- threadB.start();
- Thread.sleep(3000);
- mySevice.signalA();
- }
- }
Java基础教程:多线程基础(4)——Lock的使用的更多相关文章
- java中的多线程 // 基础
java 中的多线程 简介 进程 : 指正在运行的程序,并具有一定的独立能力,即 当硬盘中的程序进入到内存中运行时,就变成了一个进程 线程 : 是进程中的一个执行单元,负责当前程序的执行.线程就是CP ...
- Java基础教程——多线程:创建线程
多线程 进程 每一个应用程序在运行时,都会产生至少一个进程(process). 进程是操作系统进行"资源分配和调度"的独立单位. Windows系统的"任务管理器&quo ...
- Java Hour 14 多线程基础
有句名言,叫做10000小时成为某一个领域的专家.姑且不辩论这句话是否正确,让我们到达10000小时的时候再回头来看吧. 本文作者Java 现经验约为13 Hour,请各位不吝赐教. 多线程 这个是基 ...
- java开发之多线程基础篇
首先我们先来了解下线程的生命周期上一张图: Java线程具有五中基本状态 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread(); 就绪状态( ...
- Java中的多线程基础
1.线程与进程 进程: 进程是程序运行以及资源分配的基本单位,一个程序至少有一个进程. 如下图所示: 线程: 线程是CPU调度和分配的基本单位,一个进程至少有一个线程. 同一个进程中的线程共享进程资源 ...
- Java基础教程——网络基础知识
参考阅读[中国互联网发展史]:https://zhuanlan.zhihu.com/p/61602252 协议 计算机网络中的通信必须有一些约定,这些约定称为"通信协议". 通信协 ...
- JAVA学习总结-多线程基础:
参考书籍:疯狂JAVA讲义 1.进程和线程; 进程是处于运行过程中的程序;并且具有一定的独立功能;进程是系统进行系统资源分配和调度的一个独立单位. 一般而言,进程包括以下三个特征: 独立性:进程是系统 ...
- Java高并发-多线程基础
一.什么是线程 线程是进程内的执行单元. 二.线程的基本操作 2.1 状态与操作 2.2 新建线程 Thread t1 = new Thread(new CreateThread()); t1.sta ...
- php基础教程-必备基础知识
PHP 脚本在服务器上执行. 您应当具备的基础知识 在继续学习之前,您需要对下面的知识有基本的了解: HTML CSS JavaScript 如果您希望首先学习这些项目,请在我们的 首页 访问这些教程 ...
- Python笔记_第五篇_Python数据分析基础教程_NumPy基础
1. NumPy的基础使用涵盖如下内容: 数据类型 数组类型 类型转换 创建数组 数组索引 数组切片 改变维度 2. NumPy数组对象: NumPy中的ndarray是一个多维数组对象,该兑现共有两 ...
随机推荐
- ios内存管理笔记(二)
1)实现部分: 复制代码 @synthesize window=_window; @synthesize viewController=_viewController; 通常看到的都没有包含=部分,@ ...
- lua 的一些常用概念
1 a={} //定义了一个table a a[10000]=1 //这里的table中只有一个元素,10000,而不是有10000个元素 2 x=math.pi //定义了x等于π print( ...
- Hadoop之Linux源代码编译
Hadoop开篇,按惯例.先编译源代码.导入到Eclipse.这样以后要了解那块,或者那块出问题了.直接找源代码. 编译hadoop2.4.1源代码之前.必须安装Maven和Ant环境,而且Hadoo ...
- hduoj1285确定比赛名次
确定比赛名次 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total ...
- Git的提交忽略文件
.gitingore文件内容如下 /target//.settings//.classpath/.project/logs/
- hibernate 过滤
1.可以使用@Where的过滤,不过这种过滤式全局的,支持延迟加载. 2.可以使用@Filters,这种过滤不支持延迟加载. @Entity@Table(name = "qc315_tous ...
- 从有序数组中查找某个值 low_bound
二分搜索 题意: 给定长度为n的单调不下降数列a0, ...an-1和一个数k,求满足ai>=k条件的最小的i. 不存在的情况下输出n. 输入: 5 3 2 3 3 5 6 输出: ...
- 撸代码--linux进程通信(基于共享内存)
1.实现亲缘关系进程的通信,父写子读 思路分析:1)首先我们须要创建一个共享内存. 2)父子进程的创建要用到fork函数.fork函数创建后,两个进程分别独立的执行. 3)父进程完毕写的内容.同一时候 ...
- 自己定义字体之BMFont的使用
***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...
- solr入门之pinyin4j源代码改写动态加入扩展词及整合进war项目中
1.初始化时载入用户定义的字典 package net.sourceforge.pinyin4j; import net.sourceforge.pinyin4j.multipinyin.Trie; ...