Java基础教程:多线程基础(4)——Lock的使用

时间:2021-09-21 01:26:06

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的使用的更多相关文章

  1. java中的多线程 &sol;&sol; 基础

    java 中的多线程 简介 进程 : 指正在运行的程序,并具有一定的独立能力,即 当硬盘中的程序进入到内存中运行时,就变成了一个进程 线程 : 是进程中的一个执行单元,负责当前程序的执行.线程就是CP ...

  2. Java基础教程——多线程:创建线程

    多线程 进程 每一个应用程序在运行时,都会产生至少一个进程(process). 进程是操作系统进行"资源分配和调度"的独立单位. Windows系统的"任务管理器&quo ...

  3. Java Hour 14 多线程基础

    有句名言,叫做10000小时成为某一个领域的专家.姑且不辩论这句话是否正确,让我们到达10000小时的时候再回头来看吧. 本文作者Java 现经验约为13 Hour,请各位不吝赐教. 多线程 这个是基 ...

  4. java开发之多线程基础篇

    首先我们先来了解下线程的生命周期上一张图: Java线程具有五中基本状态 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread(); 就绪状态( ...

  5. Java中的多线程基础

    1.线程与进程 进程: 进程是程序运行以及资源分配的基本单位,一个程序至少有一个进程. 如下图所示: 线程: 线程是CPU调度和分配的基本单位,一个进程至少有一个线程. 同一个进程中的线程共享进程资源 ...

  6. Java基础教程——网络基础知识

    参考阅读[中国互联网发展史]:https://zhuanlan.zhihu.com/p/61602252 协议 计算机网络中的通信必须有一些约定,这些约定称为"通信协议". 通信协 ...

  7. JAVA学习总结-多线程基础&colon;

    参考书籍:疯狂JAVA讲义 1.进程和线程; 进程是处于运行过程中的程序;并且具有一定的独立功能;进程是系统进行系统资源分配和调度的一个独立单位. 一般而言,进程包括以下三个特征: 独立性:进程是系统 ...

  8. php基础教程-必备基础知识

    PHP 脚本在服务器上执行. 您应当具备的基础知识 在继续学习之前,您需要对下面的知识有基本的了解: HTML CSS JavaScript 如果您希望首先学习这些项目,请在我们的 首页 访问这些教程 ...

  9. Python笔记&lowbar;第五篇&lowbar;Python数据分析基础教程&lowbar;NumPy基础

    1. NumPy的基础使用涵盖如下内容: 数据类型 数组类型 类型转换 创建数组 数组索引 数组切片 改变维度 2. NumPy数组对象: NumPy中的ndarray是一个多维数组对象,该兑现共有两 ...

  10. cocos基础教程&lpar;4&rpar;基础概念介绍

    在Cocos2d-x-3.x引擎中,采用节点树形结构来管理游戏对象,一个游戏可以划分为不同的场景,一个场景又可以分为不同的层,一个层又可以拥有任意个可见的游戏节点(即对象,游戏中基本上所有的类都派生于 ...

随机推荐

  1. Demo中的IOC自定义实现

    在做练习的时候,小小项目,使用IOC控件觉得麻烦,使用工厂觉得不高大上啊,自己写个简陋的依赖注入IOC吧; 控制反转(IOC)是管理映射依赖的的,是依赖倒置(DIP)的实现方式; 依赖倒置(DIP)是 ...

  2. 不同版本CUDA编程的问题

    1 无法装上CUDA的toolkit 卸载所有的NVIDIA相关的app,包括NVIDIA的显卡驱动,然后重装. 2之前的文件打不开,one or more projects in the solut ...

  3. &lt&semi;Valve className&equals;&quot&semi;org&period;apache&period;catalina&period;valves&period;AccessLogValve&quot&semi; directory&equals;&quot&semi;logs&quot&semi; prefix&equals;&quot&semi;localhost&lowbar;acce

    在tomcat/conf/server.xml里的<host>标签下加上 <Valve className="org.apache.catalina.valves.Acce ...

  4. C&sol;C&plus;&plus;类型转换

    1.隐式类型转换 1.1 隐式类型转换的规则 K & R A.6.5 Arithmetic Conversions(数值型间的转换)First, if either operand is lo ...

  5. 2014&period;06&period;20 &lpar;转&rpar;IEEE与论坛灌水

    转自"饮水思源"      电子类学生大都知道IEEE, 这个IEEE就像一个大的BBS论坛,而这个协会下面有很多杂志,比如图像处理,信号处理,微波技术等.这些杂志就是论坛下的分版 ...

  6. Python爬虫第二天

    Python爬虫第二天   超时设置         有时候访问网页时长时间未响应,系统就会判断网页超时,无法打开网页.如果需要自己设置超时时间则:             通过urlopen()打开 ...

  7. linux下tomcat的https访问

    1.安装JDK(省略…) 2.安装tomcat(省略…) 3.配置SSL 进入JDK的安装目录 # cd /usr/java/jdk1..0_03/bin # ./keytool -genkey -a ...

  8. Overture如何更改音符符尾设置

    Overture作为一款专业的五线谱打谱软件,深受每一个音乐爱好者喜爱.在我们使用Overture来进行打谱操作时,往往会遇到下面这种情况:我们一般打上两个八分音符时,软件会自动符尾相连,但当我们连续 ...

  9. Kotlin 枚举类

    枚举类最基本的用法是实现一个类型安全的枚举. 枚举常量用逗号分隔,每个枚举常量都是一个对象. enum class Color{ RED,BLACK,BLUE,GREEN,WHITE } 枚举初始化 ...

  10. Ubuntu apt-get彻底卸载软件包【转】

    原文地址:https://blog.csdn.net/get_set/article/details/51276609 最近对ubuntu卸载参数的详细程度了解不够:转载已了解查用. 如果你关注搜索到 ...