Java基础教程:多线程基础(4)——Lock的使用
2024-10-11 01:23: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();
}
}
最新文章
- 整理分享原生态mac AndroidStudio的快捷键
- dojo树的节点添加链接的例子
- js的nextSibling,属性兼容IE和FF等浏览器
- 【BZOJ】1043: [HAOI2008]下落的圆盘(计算几何基础+贪心)
- android sdk 国内镜像地址
- asp.net读取txt并导入数据库
- “psp”软件需求规约
- IOS Delegate &; protocal
- 3.5MM/2.5MM耳机插头定义
- Memento:客户端瘦身
- SQL约束和字段约束的创建和删除
- ACdream 1064 完美数
- shell脚本中 杀死可能成为僵尸进程的方法
- Django_RBAC_demo2 升级版权限控制组件
- 趣味网站5个,小鸡词典/中国配色/名著地图/海洋之音/LOGO设计
- 内核开发知识第一讲.内核中的数据类型.重要数据结构.常用内核API函数.
- hash bucket
- Dockerfile 指令汇总及解析
- 创建第一个servlet程序--HelloServlet
- Sahi (3) —— 压力测试Load Test以CAS SSO登陆场景为例(103 Tutorial)
热门文章
- 转:Java 自动装箱与拆箱(Autoboxing and unboxing)
- AngularJS中,<;span class=";bluetext"; ng-bind=";ctrl.user.name|uppercase";>;<;/span>;和{{ctrl.user.name|uppercase}}是等价的,但不等于<;span class=";bluetext"; ng-bind=";ctrl.user.name|uppercase";/>;
- HDU 3591 The trouble of Xiaoqian(多重背包+全然背包)
- 使用FDTemplateLayout框架打造个性App
- apue学习笔记(第六章 系统数据文件和信息)
- iscroll的理解
- 利用DataSet部分功能实现网站登录
- linq查询去重
- Timer与ScheduledExecutorService间的抉择
- linux SPI驱动&mdash;&mdash;gpio模拟spi驱动(三)