深入ReentrantLock底层原理01
深入ReentrantLock底层原理01
1、Thread线程
package top.juntech.lock;import java.util.concurrent.locks.ReentrantLock;public class TestLock {public static void main(String[] args) {Thread t1 = new Thread(){public void run(){testSync();}};Thread t2 = new Thread(){public void run(){testSync();}};t1.setName("t1");t2.setName("t2");t1.start();t2.start();}public static void testSync(){System.out.println(Thread.currentThread().getName());try {Thread.sleep(2000);}catch (Exception e){e.printStackTrace();}}}
在这里,我们的线程t1,t2同时调用了testSync方法,尽管有thread.sleep(2000),但我们发现t1,t2几乎是同时打印出来的,为什么呢,在t1进入这个方法里面,虽然在睡眠但不影响主线程继续执行,接下来t2启动,那我们怎么使他们一前一后执行呢,答案时加锁。我们这里就将ReentranLock.
1、添加一个全局变量: ReentranLock reen = new ReentranLock(true);
2、在方法里面添加lock方法
3、释放锁
代码如下:
package top.juntech.lock;import java.util.concurrent.locks.ReentrantLock; //初始化锁对象public class TestLock {static ReentrantLock reentrantLock = new ReentrantLock(true);public static void main(String[] args) {Thread t1 = new Thread(){public void run(){testSync();}};Thread t2 = new Thread(){public void run(){testSync();}};t1.setName("t1");t2.setName("t2");t1.start();t2.start();}public static void testSync(){try {reentrantLock.lock(); //加锁System.out.println(Thread.currentThread().getName());try {Thread.sleep(2000);}catch (Exception e){e.printStackTrace();}}finally {reentrantLock.unlock(); //释放锁}}}
这样,我们就可以看到t1打印完了过了2s左右,才开始打印t2.
2、思考
既然java里面有关键字sysnchronized,为什么还需要ReentranLock?
java中的线程是和操作系统中的线程是一一对应的,synchronized在执行多线程时,t1进入synchronized方法后,t2也想进去,它会让t2操作操作系统的一个函数,t2占用之后,会让操作系统的哪个函数产生阻塞,直到t1醒来,执行完释放,t2拿到锁之后,接着执行同步代码块。
2.1 多线程同步内部是如何实现的
wait/notify,synchronized ,ReentranLock
模拟一些同步的思路:
自旋锁:
volatile int status = 0;
void lock(){while(!compareAndSet(0,1)){}//lock
}
void unlock(){status = 0;
}
boolean compareAndSet(int except,int newValue){//compare and set操作,修改status成功返回true
}
缺点: 耗费cpu资源,没有竞争到锁的线程会一直占用cas操作。
思路:让得不到锁的线程让出cpu
不能用wait,因为wait是和sync一起使用的,单独使用会报错,且wait不只是拿来使线程阻塞的,它还可以用来线程通信。
yield+自旋锁
volatile int status = 0;
void lock(){while(!compareAndSet(0,1)){yield();//自己实现 }//lock
}
void unlock(){status = 0;
}
boolean compareAndSet(int except,int newValue){//compare and set操作,修改status成功返回true
}
要解决自旋锁的性能问题必须让竞争锁失败的的线程不空转,而是在获取不到锁的时候让出cpu,yeild()方法可以让出cpu;但是yield并不能完全解决问题,在线程数为2个时,可以使用,但线程数比较多的时候,就不适用了,因为yeild是由操作系统控制的。
yield方法,请参考:https://blog.csdn.net/zhuwei898321/article/details/72844506
sleep+自旋锁
volatile int status = 0;
void lock(){while(!compareAndSet(0,1)){sleep(10};//自己实现 }//lock --- 1s
}
void unlock(){status = 0;
}
boolean compareAndSet(int except,int newValue){//compare and set操作,修改status成功返回true
}
缺点:睡眠时间不确定,易造成cpu资源浪费
park+自旋锁
这里要使用的是UNSAFE类里面的park方法,下面是park方法的具体使用
package top.juntech.lock;import java.util.concurrent.locks.LockSupport;public class TestPark {public static void main(String[] args) {Thread t1 = new Thread(){public void run(){testSync();}};t1.setName("t1");t1.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("--------main-------"); // 3、打印mainLockSupport.unpark(/*线程名*/t1); //4、叫醒t1,继续执行,打印t1---2}public static void testSync(){System.out.println(/*Thread.currentThread().getName()*/ "t1 -----1"); //1.首先打印t1 --1LockSupport.park(); //2.t1开始睡眠System.out.println("t1 ----- 2");}
}
伪代码如下:
volatile int status = 0;
Queue parkQueue; //集合 数组
void lock(){while(!compareAndSet(0,1)){park();}//lock 20sunpark();
}
void unlock(){status = 0;lock_notify();
}
boolean compareAndSet(int except,int newValue){//compare and set操作,修改status成功返回true
}
void park(){//将当前线程添加到等待队列parkQueue.add(currentThread)//将当前线程释放cpu,阻塞releaseCpu();
}
void lock_notify(){//得到要唤醒的线程头部线程Thread t = parkQueue.header();//唤醒等待线程unpark(t);
}
更多详情
设置为vip可见的都可访问下面链接地址,即可观看原文
更多详情请访问: juntech
深入ReentrantLock底层原理01相关推荐
- 【多线程学习笔记】sychronized关键字底层原理、sychronized与ReentrantLock、volatile和synchronized
文章目录 sychronized释义 synchronized关键字最主要的三种使用方式: synchronized底层原理: 同步代码块: 同步方法 当前类的class对象作为锁 锁升级 Synch ...
- 并发底层原理:线程、资源共享、volatile 关键字
并发底层原理:线程.资源共享.volatile 关键字 1.线程 1.1 定义任务 1.2 Thread 类 1.3 使用 Executor 1.4 从任务中产生返回值 1.6 优先级 1.7 后台线 ...
- java锁的底层原理
知识整理 Synchronized 内置锁,JVM级别 使用 底层 锁升级过程.CAS操作的缺点[替换线程和copy mw] 优化 代码优化:同步代码块.减少锁粒度.读锁并发 JDK自带 偏置锁.轻量 ...
- 嘿嘿,我就知道面试官接下来要问我 ConcurrentHashMap 底层原理了,看我怎么秀他...
来自:烟雨星空 前言 上篇文章介绍了 HashMap 源码后,在博客平台广受好评,让本来己经不打算更新这个系列的我,仿佛被打了一顿鸡血.真的,被读者认可的感觉,就是这么奇妙. 原文:面试官再问你 Ha ...
- SQL 中 left join 的底层原理(各种JOIN的复杂度探究)
01. 前言 写过或者学过 SQL 的人应该都知道 left join,知道 left join 的实现的效果,就是保留左表的全部信息,然后把右表往左表上拼接,如果拼不上就是 null.除了 left ...
- 你知道 Sql 中 left join 的底层原理吗?
总第165篇/张俊红 01.前言 写过或者学过 Sql 的人应该都知道 left join,知道 left join 的实现的效果,就是保留左表的全部信息,然后把右表往左表上拼接,如果拼不上就是 nu ...
- java aqs详解_Java AQS底层原理解析
AQS底层原理 AQS(AbstractQueuedSynchronizer)是一个抽象同步队列,JUC(java.util.concurrent)中很多同步锁都是基于AQS实现的. AQS的基本原理 ...
- synchronized的使用和底层原理、锁状态的膨胀升级过程
文章目录 1. synchronized介绍 2. synchronized底层原理 3. synchronized锁的膨胀升级过程 4. synchronized锁状态的记录位置 5. synchr ...
- Java并发编程-synchronized底层原理
synchronized底层原理与Monitor密切相关 1.Java对象头 以 32 位虚拟机为例 普通对象 对象的类型,如Student类型,Teacher类型等是由KlassWord来表示的,它 ...
- synchronized原理_面试必备—Synchronized 关键字使用、底层原理
在并发编程中存在线程安全问题,主要原因有: 1.存在共享数据 2.多线程共同操作共享数据 关键字synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,同时synchro ...
最新文章
- 实现一个基于 SharePoint 2013 的 Timecard 应用(下)
- bt下载加速 BitTorrent trackers服务器列表
- Advanced Transact-SQL for SQL Server 2000 学习译文
- html:(24):内联式css和嵌入式css
- android 开源项目列表【持续整理中。。。】
- windows 7 64bit python3.3安装pyqt
- 如何在单例模式下禁止init
- 吴恩达机器学习(十)支持向量机(SVM)
- matlab做叠加定理仿真,实验一 仿真软件的使用与叠加原理的验证
- OPPO R9KM手机刷机救砖线刷包附驱动教程
- 世界上最好的惯性动作捕捉设备Xsens,你不应该错过的Xsens MVN Animate Pro
- 计算机关闭没用的端口,关闭端口的方法,小编教你如何关闭电脑不用的端口
- JAVA代码实现计算器功能
- reboot流程简述
- dcos 正确的查看日志的姿势
- 瑞萨开发记录01:点亮一颗LED灯(R5F104FEA芯片)
- 如何在头条做营销:2022今日头条营销价值洞察报告.pdf(附下载链接)
- 学习学习学习学习学习学习
- 两条命令彻底修复动态链接库
- APMServ 使用