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是一个多维数组对象,该兑现共有两 ...
随机推荐
- 不得不知Git远程操作详解
Git是目前最流行的版本管理系统,学会Git几乎成了开发者的必备技能. Git有很多优势,其中之一就是远程操作非常简便.本文详细介绍5个Git命令,它们的概念和用法,理解了这些内容,你就会完全掌握Gi ...
- struts2设置默认首页
在默认情况下,我们一般希望.当我们在浏览器中输入127.0.0.1:8080/project_name时候跳到项目的首页,那么在struts中我们这么设置呢?光加上<default-action ...
- 2016.7.5 如何在maven中添加所需依赖(只知道jar包的部分名字的情况)
(1)进入官网仓库 http://mvnrepository.com/ (2)输入需要的jar包名 比如这里的jota-time (3)寻找需要的版本,并选取需要的版本 (4)复制需要的maven依赖 ...
- 一个端口划到多个VLAN
不想启路由的情况下,希望将一个端口划到多个VLAN中去,其目的有如下几点: 1.隔离不想让相互访问的端口.(如两个部门) 2.让都需要访问的端口划到所有VLAN.(如共享服务器) 3.不启路由协议.( ...
- Java数据结构和算法(四)——栈
stack,中文翻译为堆栈,事实上指的是栈,heap,堆. 这里讲的是数据结构的栈,不是内存分配里面的堆和栈. 栈是先进后出的数据的结构,好比你碟子一个一个堆起来.最后放的那个是堆在最上面的. 队列就 ...
- Shell脚本之:字符串
字符串可以用单引号,也可以用双引号,也可以不用引号. 单引号 str='this is a string' 单引号字符串的限制: 1.单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的: 2 ...
- mongodb:monogo和php整合
1.到如下网址,下载php扩展包,找一个最新stable版的.
- 《C陷阱与缺陷》学习笔记(一)
前言和导读 "得心应手的工具在初学时的困难程度往往超过那些easy上手的工具."比較认同这句话. 我至今认为自己事实上还是个刚入了门的刚開始学习的人. 第一章 "词法&q ...
- Python数据结构:列表、元组和字典
在Python中有三种内建的数据结构——列表list.元组tuple和字典dict 列表中的项目包括在方括号中,项目之间用逗号分割 元组和列表十分类似,只不过元组和字符串一样是不可变的 即你不能修改元 ...
- java获取网页源码
获取网页的源码: package com.atguigu.crud.controller; import java.io.BufferedReader; import java.io.Buffered ...