我们面试中经常会被问到多线程相关知识,这一块内容往浅了说大家都会,但是一问到底层实现原理,我们往往就一脸懵逼。

这段时间准备好好学习多线程,接下来会写一系列关于多线程的知识。

我们首先要了解线程,百度百科这么介绍:线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程每条线程并行执行不同的任务

这句话很好理解。一般我们不创建 thread 类的话,程序都是单线程在执行。

线程是有多种状态的,Thread 类里有个枚举变量 State 列举了线程的几种状态

下面这张图说明了线程状态之间的关系。

程序里有多个线程时,会出现多个线程对同一个对象操作的情况,为了保证同一时间只能有一个线程操作该对象,就引入了锁机制。

锁有分布式锁,java锁 ,java 锁有 synchronized 关键字,Lock 锁。今天我们主要讲 java 中的 Lock 锁。

常用的可重入锁(ReentrantLock)就是实现了 Lock 接口,这次我们就尝试自己制作一把锁,当然我们要实现 Lock 接口。

首先来分析如何实现它?

1.需要一个线程的等待集合,所以我们要定义一个list,考虑到先进先出机制,我们用 LinkedBlockingQueue 来存放线程集合

2.需要一个锁标记,来记录当前持有锁的进程,考虑到它的原子性,我们用 AtomicReference 类来存放

3.线程执行完,会释放锁,此时要通知其他线程争抢锁,这里又涉及到线程通信。

下图也是我的分析过程,我们接下来就用代码来实现。

实现之前,我们先了解一些线程通信的知识,我们最常用的方法是 wait/notify,但是 wait/notify 有一个很明显的缺点,正常顺序是 先 wait,再 notify,如果程序先 notify,再 wait,就会进入死锁状态,所以它是有顺序限制的,但是 park/unpark 方法就不会有这些问题,所以我们用 park/unpark 实现线程通信。

下面是实现代码,注释里写的很清楚了。

public class MyLock implements Lock {

    //判断是否有人拿到锁
AtomicReference<Thread> owner = new AtomicReference<>();
//等待线程队列
LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>(); @Override
public boolean tryLock() {
//如果 owner 为空,就把当前线程赋给 owner
return owner.compareAndSet(null,Thread.currentThread());
} @Override
public void lock() {
boolean park = false;
while(!tryLock()){
if(!park){
//加入等待集合
waiters.offer(Thread.currentThread());
park = true;
}else{
LockSupport.park();
}
}
waiters.remove(Thread.currentThread()); } @Override
public void unlock() {
//释放锁,要通知等待者
if(owner.compareAndSet(Thread.currentThread(),null)){
//遍历等待者 ,通知继续执行
Thread next = null;
while ((next = waiters.peek() )!= null){
LockSupport.unpark(next);
} }
} @Override
public void lockInterruptibly() throws InterruptedException {
} @Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
} @Override
public Condition newCondition() {
return null;
}
}

Lock 接口里,还有一些方法没有实现,当然这都不重要,主要是为了实现 lock 和 unlock 方法。

研究多线程,要多看看 java.util.concurrent 包,把这个包研究透了,多线程也就学的差不多了。毕竟面试中多线程用的还是挺多的。

多线程系列之自己实现一个 lock 锁的更多相关文章

  1. 一个lock锁就可以分出低中高水平的程序员对问题的处置方式

    说到lock锁,我相信在座的各位没有不会用的,而且还知道怎么用不会出错,但让他们聊一聊为什么可以锁住,都说人以群分,大概就有了下面低中高水平的三类人吧. 第一类人 将lock对象定义成static,这 ...

  2. c#多线程实现定时执行代码与lock锁操作

    总结以下三种方法,实现c#每隔一段时间执行代码: 方法一:调用线程执行方法,在方法中实现死循环,每个循环Sleep设定时间: 方法二:使用System.Timers.Timer类: 方法三:使用Sys ...

  3. 使用Lock锁生产者消费者模式

    package com.java.concurrent; import java.util.concurrent.locks.Condition; import java.util.concurren ...

  4. Java多线程系列--“JUC锁”03之 公平锁(一)

    概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...

  5. Java多线程系列--“JUC锁”04之 公平锁(二)

    概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...

  6. Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例

    概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)Cyc ...

  7. Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock

    本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLo ...

  8. Java多线程系列--“JUC锁”01之 框架

    本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--“JUC锁”01之 框架02. Java多线程系列--“JUC锁”02之 互斥锁Reentrant ...

  9. Java多线程系列--“JUC锁”06之 Condition条件

    概要 前面对JUC包中的锁的原理进行了介绍,本章会JUC中对与锁经常配合使用的Condition进行介绍,内容包括:Condition介绍Condition函数列表Condition示例转载请注明出处 ...

随机推荐

  1. js 实现异步上传图片+预览

    两种js实现方式,一种用原生的ajax:另一种用JQuery,例子比较简单,直接上代码. <!DOCTYPE html> <html> <head> <tit ...

  2. 静态方法和实例方法(mark)

    借花献佛[转自 ivony's blog] 关于静态方法和实例方法的一些误区. 一.    静态方法常驻内存,实例方法不是,所以静态方法效率高但占内存.     事实上,方法都是一样的,在加载时机和占 ...

  3. C# 比较两文本相似度

    这个比较文本用到的主要是余弦定理比较文本相似度,具体原理右转某度,主要适用场景是在考试系统中的简答题概述,可根据权重自动打分,感觉实用性蛮广的. 先说下思路: 文本分词,中文于英文不同,规范的英文每个 ...

  4. optimal-account-balancing

    一群朋友去度假,有时互相借钱. 例如,爱丽丝为比尔的午餐支付了 10 美元.后来克里斯给爱丽丝 5 美元搭出租车.我们可以假设每笔交易为一个三元组(X,Y,Z),这意味着第 X 个人借给第 Y 个人  ...

  5. centos7初上手2-安装tomcat服务

    上一篇文章说完安装mysql数据库,这篇文章来学习一下tomcat安装 1.先做准备工作,安装jdk,先看服务器上有没有安装相关java文件 下载好1.8版本的安装包,用xftp传到服务器上(根据个人 ...

  6. putty导出、导入数据库

    e.g 从223服务器导数据库的t_marine_area到227服务器 用putty连接223服务器 导出数据库命令:pg_dump -h localhost -U postgres -d mari ...

  7. Ubuntu 18.04安装中文输入法

    reference: https://blog.csdn.net/fx_yzjy101/article/details/80243710 https://pinyin.sogou.com/linux/ ...

  8. Python知识体系思维导图:

    基础知识 数据类型 1.序列 2.字符串 3.列表和元组 4.字典和集合 循环 & 判断

  9. IIS--------问题解决(localhost可以访问,本地ip不可以)

    api:localhost可以访问,本地ip就不可以,报错:405 解决方案:api项目 - 属性 - web - 服务器 将:iis-express 改为 本地iis 创建虚拟目录:eg:http: ...

  10. PAT A1059

    PAT A1059 标签(空格分隔): PAT 解题思路 :先打印出素数表.利用结构体数组来存贮质因子的值和个数 strcut factor{ int x; //值 int cnt; //个数 }fa ...