java锁原理_Java锁原理学习
Java锁原理学习
为了学习Java锁的原理,参照ReentrantLock实现了自己的可重入锁,代码如下:
先上AQS的相关方法:
// AQS = AbstractQueuedSynchronizer, 抽象队列同步器
// 它提供了对资源的占用、释放,线程的等待、唤醒等接口和具体实现
// 它维护了一个volatile int state来代表共享资源的状态,和一个FIFO线程等待队列
// 获取排它锁
// 先尝试获取锁,如果获取不到则添加到等待队列
// 等待队列通过 LockSupport.park(this) 实现等待
// 通过 LockSupport.unpark(s.thread) 实现唤醒
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// 默认的tryAcquire抛出异常,需要子类实现
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
// 释放锁
// 尝试释放,如果成功则唤醒等待的线程
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
// 默认的tryRelease抛出异常,需要子类实现
// 返回值true时表示当前线程已完全释放该锁(因为可重入所以需要多次release),否则返回false
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
// 等待条件锁
public final void await() throws InterruptedException {
// 1. 保存当前线程的锁状态(即state的值)
// 2. 调用 LockSupport.park(this); 实现等待
// 3. 被唤醒后重新尝试获取锁
}
// 条件等待唤醒,仅唤醒等待队列的第一个线程
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
// 条件唤醒,唤醒等待队列的所有线程
public final void signalAll() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignalAll(first);
}
// signal()和signalAll()最终都调用该方法唤醒特定线程
final boolean transferForSignal(Node node) {
// LockSupport.unpark(node.thread);
}
以下是自己实现的MyLock:
public static class MyLock extends AbstractQueuedSynchronizer {
/**
*
*/
private static final long serialVersionUID = 1L;
// 加锁方法通过aqs的acquire方法实现,样例仅实现排它锁功能
public void lock() {
acquire(1);
}
// 尝试获取锁,子类需实现该方法,核心是设置aqs中state的值
@Override
protected boolean tryAcquire(int n) {
int c = getState();
Thread t = Thread.currentThread();
// 如果c为0则表示当前锁没有被占用
if (c == 0) {
// 如果没有前序线程,则通过CAS尝试设置state值为申请的资源数
if (!hasQueuedPredecessors() && compareAndSetState(0, n)) {
// 如果获取锁成功则需要记录当前持有锁的线程,用于后续可重入和释放锁
setExclusiveOwnerThread(t);
return true;
}
// 如果当前线程已持有该锁则直接更新state值为总的资源数
} else if (t == getExclusiveOwnerThread()) {
setState(c + n);
return true;
}
return false;
}
// 释放锁通过aqs的release方法实现
public void unlock() {
release(1);
}
// 尝试释放锁,子类需实现该方法
// 首先判断当前线程是否持有该锁,否则抛出异常
// 更新state的值,如果已完全释放则设置当前持有排它锁的线程为null并返回true,否则返回false
@Override
protected boolean tryRelease(int n) {
if (getExclusiveOwnerThread() != Thread.currentThread()) {
throw new IllegalMonitorStateException();
}
int c = getState() - n;
setState(c);
if (c == 0) {
setExclusiveOwnerThread(null);
}
return c == 0;
}
// 创建条件锁
// 条件等待:cond.await();
// 条件满足通知:cond.signal(); 或cond.signalAll();
public Condition newCondition() {
return new ConditionObject();
}
@Override
protected boolean isHeldExclusively() {
return this.getExclusiveOwnerThread() == Thread.currentThread();
}
}
测试程序:
public static void main(String[] args) {
MyLock lock = new MyLock();
// 使用MyLock或ReentrantLock结果相同
// ReentrantLock lock = new ReentrantLock();
Condition c = lock.newCondition();
Runnable run = () -> {
String n = Thread.currentThread().getName();
lock.lock();
lock.lock();
System.err.println("i am " + n);
try {
if (n.equals("t1")) {
c.await();
} else {
c.signal();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
lock.unlock();
System.err.println(n + " finished");
};
new Thread(run, "t1").start();
new Thread(run, "t2").start();
}
// 输出
i am t1
i am t2
t2 finished
t1 finished
以下补充Semaphore的原理:
Semaphore是一个计数信号量,必须由获得它的线程释放,常用于限制可以访问资源的线程数量。
// 用法
// 初始化指定数量的许可证
Semaphore s = new Semaphore(2);
// 需要获取的许可证数量
s.acquire(2);
// 需要释放的许可证数量
s.release(2);
// 实现
public class Semaphore {
private final Sync sync;
// 通过AQS实现
abstract static class Sync extends AbstractQueuedSynchronizer {
Sync(int permits) {
setState(permits);
}
}
// 获取直接调用AQS的acquire方法
public void acquire(int permits) throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireSharedInterruptibly(permits);
}
// 释放同样直接调用AQS的release方法
public void release(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.releaseShared(permits);
}
}
java锁原理_Java锁原理学习相关推荐
- java锁实现_Java锁实现
java锁实现 我们都将第三方库用作开发的正常部分. 通常,我们无法控制其内部. JDK随附的库是一个典型示例. 这些库中的许多库都使用锁来管理争用. JDK锁具有两种实现. 一个使用原子CAS样式指 ...
- java 全局变量 加锁_Java锁机制(一)synchronized
进行多线程编程的时候,需要考虑的是线程间的同步问题.对于共享的资源,需要进行互斥的访问.在Java中可以使用一些手段来达到线程同步的目的: 1. synchronized 2. ThreadLocal ...
- java并发进程共享变量_JAVA并发编程学习:共享对象
可见性 在一个单线程程序中,如果向一个变量先写入值,然后在没有写干涉的情况下读取这个变量,会得到相同的返回值.但是当读和写发生在不同的线程中时,就不能保证读线程及时地读取其他线程写入的值.在JAVA中 ...
- java linkedlist实例_Java Linkedlist原理及实例详解
这篇文章主要介绍了Java Linkedlist原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 定义:linkedlist属于链表结构 ...
- java nio 事件_Java NIO原理及实例
Java NIO是在jdk1.4开始使用的,它既可以说成"新I/O",也可以说成非阻塞式I/O.下面是java NIO的工作原理: 1. 由一个专门的线程来处理所有的 IO 事件, ...
- java thread类_Java多线程原理及Thread类详解
多线程原理 代码如下: 自定义线程类: 测试类: 流程图: 程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建.随着调用mt的对象的start方法,另外一 ...
- java数组原理_Java数组排序原理
Arrays排序原理 Java Arrays排序原理 计数排序源码 (short为例) for (int i = left - 1; ++i <= right;count[a[i] - Sh ...
- java 匿名内部类 参数_Java匿名内部类原理与用法详解
本文实例讲述了Java匿名内部类原理与用法.分享给大家供大家参考,具体如下: 一 点睛 匿名内部类适合创建那种只需要一次使用的类,定义匿名内部类的语法格式如下: new 父类构造器(实参列表) | 实 ...
- java 断点续传 开源_java断点续传原理
先说说断点续传的原理:这是HTTP 1.1协议的一部分,并不需要客户端特意去做多么复杂的事情.以前我曾经看过一个单位的技术标书,其中有下载的断点续传这一要求,给出的offer居然还挺高的... 简单的 ...
最新文章
- 数据分析必备:掌握这个R语言基础包1%的功能让你事半功倍!(附代码)
- centos mysql拒绝连接失败_CentOS下mysql远程连接的失败的解决方法
- 历时八年 HTML5标准终于制定完成
- linux命令find
- 学习Docker从小白到入门
- springboot拦截请求路径_SpringBoot整合Ant Design Pro进行部署
- C# XML反序列化与序列化举例:XmlSerializer(转)
- SQLServer中round函数
- linux command read the content,Linux while 和 read 的用法
- PAT 1086 就不告诉你
- 用Java实现md5加密
- 判断一个数是否是素数
- 渗透测试之敏感信息收集
- 模仿dos窗口下的windows窗口程序
- 怎么去除视频字幕清理视频字幕或水印的几种方法
- 【数据库】编写存储过程
- 《刻意练习》--读后感1
- 瑞萨RH850 FCL、FDL和EEL库的配置和使用
- 扬长避短,做自己最擅长的事情
- subprocess.Popen()