手写非公平可重入锁

公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。

优点:所有的线程都能得到资源,不会饿死在队列中。

缺点:吞吐量会下降很多,队列里面除了第一个线程,其他的线程都会阻塞,cpu唤醒阻塞线程的开销会很大。

非公平锁:多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获取到,就直接获取到锁。

优点:可以减少CPU唤醒线程的开销,整体的吞吐效率会高点,CPU也不必取唤醒所有线程,会减少唤起线程的数量。

缺点:你们可能也发现了,这样可能导致队列中间的线程一直获取不到锁或者长时间获取不到锁,导致饿死。

不可重入锁:只判断这个锁有没有被锁上,只要被锁上申请锁的线程都会被要求等待。实现简单

可重入锁:不仅判断锁有没有被锁上,还会判断锁是谁锁上的,当就是自己锁上的时候,那么他依旧可以再次访问临界资源,并把加锁次数加一。

importjava.util.concurrent.LinkedBlockingDeque;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.atomic.AtomicInteger;importjava.util.concurrent.locks.Condition;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.LockSupport;public class MyLock implementsLock {//锁的状态 0 - 未占用 1 - 占用

AtomicInteger state = newAtomicInteger();//当前占用的线程

Thread ownerThread = null;//当前等待抢锁的线程

LinkedBlockingDeque waiters = new LinkedBlockingDeque<>();

@Overridepublic voidlock() {if (!tryLock()) {

waiters.add(Thread.currentThread());//1. 先排队

for(;;) {if(tryLock()) {//如果某一个线程抢到了锁,自己把自己从队列里面挪出来

waiters.poll();return;

}else{

LockSupport.park();//2. 等呗 -- 等待到何时再执行?唤醒目的是继续抢锁

}

}

}

}

@Overridepublic voidunlock() {if (ownerThread !=Thread.currentThread()) {throw new RuntimeException("非法调用---当前这个锁不属于你");

}if (state.decrementAndGet() == 0) { //减1等0 - 0代表锁未被占用

ownerThread = null;//通知其他正在等待的线程

Thread waiterThread = waiters.peek();//取出队列的第一个(但队列中仍然存在)FIFO先进先出

LockSupport.unpark(waiterThread);

}

}

@Overridepublic booleantryLock() {//把 0 - 1

if (state.get() == 0) {//CAS 底层c++实现 保证N个线程同事操作,只有一个线程操作成功

if (state.compareAndSet(0, 1)) {

ownerThread=Thread.currentThread();return true;

}

}else if (ownerThread == Thread.currentThread()) { //如果占用锁就是当前线程,则代表重入

state.set(state.get() + 1);return true;

}return false;

}

@Overridepublic boolean tryLock(long time, TimeUnit unit) throwsInterruptedException {return false;

}

@OverridepublicCondition newCondition() {return null;

}

@Overridepublic void lockInterruptibly() throwsInterruptedException {

}

}

importjava.util.Date;importjava.util.concurrent.locks.ReentrantLock;public classLockDemo {//static Lock lock = new ReentrantLock();//默认非公平

static MyLock lock = newMyLock();//new ReentrantLock(true); 公平锁

public static void main(String[] args) throwsInterruptedException {//主线程获取到锁

lock.lock(); //其他没有获取到锁 阻塞 卡住不动

System.out.println("主线程获取到锁 其他线程卡住不动 " + Thread.currentThread().getName() + newDate());

Thread thread= new Thread(newRunnable() {

@Overridepublic voidrun() {

lock.lock();

System.out.println(Thread.currentThread().getName()+ "---子线程获取到锁---");

lock.lock();

System.out.println(Thread.currentThread().getName()+ "---子线程第2次获取到锁---");

lock.unlock();

System.out.println(Thread.currentThread().getName()+ "---子线程释放锁---");

lock.unlock();

System.out.println(Thread.currentThread().getName()+ "---子线程第2次释放锁---");

}

});

thread.start();//主线程睡眠3s

Thread.sleep(3000L);

System.out.println("3s后主线程释放锁 其他线程可以开始抢锁 " + Thread.currentThread().getName() + newDate());

lock.unlock();

}

}

打印结果

主线程获取到锁 其他线程卡住不动 mainSat May 23 23:16:22 CST 20203s后主线程释放锁 其他线程可以开始抢锁 mainSat May23 23:16:26 CST 2020Thread-0---子线程获取到锁---Thread-0---子线程第2次获取到锁---Thread-0---子线程释放锁---Thread-0---子线程第2次释放锁---

可重入锁使用案例

/**

* 文件所有的文件名增加一个前缀

* @param dir

* @param prefix

*/

public void fileRename(String dir, String prefix) {

lock.lock();

try {

File file = new File(dir);

File[] files = file.listFiles();

for (File f : files) {

if (f.isDirectory()) {

fileRename(f.getPath(), prefix);

} else {

file.renameTo(new File("新名字"));

}

}

} finally {

lock.unlock();

}

}

手写java_手写java锁相关推荐

  1. 手写java_手写JAVA虚拟机(二)——实现java命令行

    咱们都知道,咱们编译.java并运转.class文件时,需求一些java指令,如最简略的helloworld程序.java初学者可以看一下下面的教程. 这儿的程序最好不要加包名,因为加了包名的话编译和 ...

  2. 手牵手教你写代码,从入门到精通

    如果说到什么是好代码,我们肯定都能说出一堆规则,例如使用一致的格式和缩进.使用清晰的变量名和方法名.在必要时提供文档与注释.不要过度精简代码等等. 但是对于什么是烂代码,你有比较清晰的认识吗? 在 G ...

  3. 【手写系列】写一个迷你版的Tomcat

    前言 Tomcat,这只3脚猫,大学的时候就认识了,直到现在工作中,也常会和它打交道.这是一只神奇的猫,今天让我来抽象你,实现你! Tomcat Write MyTomcat Tomcat是非常流行的 ...

  4. 【手写系列】写出我的第一个框架:迷你版Spring MVC

    你没有看错标题,今天,我将实现我人生中第一个框架,^_^ 前期准备 我这里要写的是一个迷你版的Spring MVC,我将在一个干净的web工程开始开发,不引入Spring,完全通过JDK来实现. 我们 ...

  5. 【用MFC写串口调试助手】

    用MFC写串口调试助手 界面设计 各控件说明 串口控件的插入 程序设计 初始化函数添加 串口检测按钮相关函数 打开按钮相关函数 发送数据按钮相关函数 点选定时发送复选框 点选HEX发送复选框相关函数 ...

  6. getconnection java_在MyEclipse用java写的一个GetConnection1.java,用于连接MySQL,却总是出错。(没有财富值了,见谅!)...

    在MyEclipse用java写的一个GetConnection1.java,用于连接MySQL,却总是出错.求救!!!packageJavaBean1;importjava.sql.*;import ...

  7. 写一个简单的Java界面程序

    写一个简单的Java界面程序 有时候未免想写一些有界面的java小程序练练手,那么如何写一个比较好看的界面话程序呢?下面小编就带你一步一步来搭建这个小洋房. 实现界面化编程要用到的一个主要包impor ...

  8. 用java做一个简单记事本_用记事本写一个简单的java程序

    用记事本写一个简单的java程序 第一步: 安装好jdk,并设置好环境变量. 桌面-计算机(右键)-属性-高级系统设置-环境变量-path-在变量值后加上:和jdk安装路径加上(路径即为C:\Prog ...

  9. 像写SQL一样编写Java数据应用-TinySqlDsl

    前言 话说企业应用,一般离不开数据库.要做数据库,可以有N种方案,比如:直接采用JDBC层自己封装下使用的,采用一些框架的,如:iBatis,Hiberate,Spring JDBC Template ...

最新文章

  1. RDKit | 化合物亚结构搜索与结果输出
  2. 一些常规形几何形状的绘制和效果填充(三)
  3. sklearn自学指南(part43)--数据加载工具
  4. python可以在linux运行_服务器(Linux)上运行python总结
  5. python中赋值运算符有哪些_Python代码中有哪些赋值运算符呢?
  6. 二级菜单打开一个时其他关闭_blender2.8教程 顶部菜单栏
  7. linux运维需要掌握的基础知识
  8. LoadRunner如何建立关联
  9. u8文件服务器在哪设置,u8 设置文件服务器
  10. photoshop cs6视频教程(从入门到精通)
  11. 英语语音篇 - 元音自然拼读
  12. 36. linux系统日志在哪里看
  13. Lipschitz条件
  14. 扫描至计算机功能被禁用,远程访问功能已禁用怎么办_允许远程界面控制被禁用的解决方法...
  15. 无我编程的10条诫律
  16. 要想文章上Google搜索引擎首页,SEO 要做好下面7个点优化
  17. 个人支付宝/微信/云闪付收款技术总览
  18. Win10 Plants VS Zombies 运行时出现 Fatal Error
  19. 细胞治疗CAR_T行业深度报告:细胞治疗,七载归来方始坼-20210706-兴业证券
  20. 基本电路概念(二)什么是电容?

热门文章

  1. 6. 成交量基础分析
  2. PureFTP安装配置
  3. Android开发笔记1之HelloWorld
  4. C++ 删除字符串的首尾空字符
  5. SQL Server 2005 Service Pack 2 – CTP December 2006发布
  6. 42 - 算法 - 198-打家劫舍-动态规划
  7. MySQL数据库基础(mysql数据类型、数据表的操作)
  8. 微课|中学生可以这样学Python(例9.1):Excel导入SQLite(1)
  9. Python使用空域融合技术进行图像去噪
  10. java迷宫_java实现迷宫算法--转