同步器

动手实现一个同步器(AQS)

感情迁移 提交于 2020-02-27 00:27:20
在多线程情景下,如果不会某一共享变量采取一些同步机制,很可能发生数据不安全现象,比如购买车票时,当多个人购买时,不加锁就会产生多人买同一张票的现象,显然这是不可取的。所以要有一种同步机制,在某一时刻只能有一个线程处理该共享变量。 同步器的加锁 我将自己实现的同步器成为RoadAQS. 主要变量如下: //当前锁的状态,1表示加锁,0表示未加锁 private volatile int state = 0; private final static Unsafe unsafe = UnsafeInstance.reflectUnsafe(); //state在内存中的偏移量 private final static long stateOffset; //当前持有锁的线程 private Thread lockHoder; //是一个线程安全的队列,记录等待获取锁的线程 private ConcurrentLinkedQueue<Thread> waiters = new ConcurrentLinkedQueue<>(); static { try { stateOffset = unsafe.objectFieldOffset(RoadAQS.class.getDeclaredField("state")); } catch (NoSuchFieldException e) {

线程同步器CountDownLatch

邮差的信 提交于 2020-02-16 13:37:59
  Java程序有的时候在主线程中会创建多个线程去执行任务,然后在主线程执行完毕之前,把所有线程的任务进行汇总,以前可以用线程的join方法,但是这个方法不够灵活,我们可以使用CountDownLatch类,实现更优雅,而且使用线程池的话,可没有办法调用线程的join方法的呀! 一.简单使用CountDownLatch   直接使用线程: package com.example.demo.study; import java.util.concurrent.CountDownLatch; public class Study0215 { //这里相当于新建一个初始值为2的计数器 private static volatile CountDownLatch countDownLatch = new CountDownLatch(2); public static void main(String[] args) throws InterruptedException { new Thread(()->{ try { Thread.sleep(1000); System.out.println("线程一执行完毕"); } catch (Exception e) { }finally { //每调用这个方法计数器减一 countDownLatch.countDown(); } })

1.3.1 AQS抽象队列同步器详解

拟墨画扇 提交于 2020-02-15 04:13:29
什么是AQS AQS(AbstractQueuedSynchronizer),AQS是JDK下提供的一套用于实现基于FIFO等待队列的阻塞锁和相关的同步器的一个同步框架。这个抽象类被设计为作为一些可用原子int值来表示状态的同步器的基类。如果你有看过类似 CountDownLatch 类的源码实现,会发现其内部有一个继承了 AbstractQueuedSynchronizer 的内部类 Sync 。可见 CountDownLatch 是基于AQS框架来实现的一个同步器.类似的同步器在JUC下还有不少。(eg. Semaphore ) AQS用法 如上所述,AQS管理一个关于状态信息的单一整数,该整数可以表现任何状态。比如, Semaphore 用它来表现剩余的许可数,ReentrantLock 用它来表现拥有它的线程已经请求了多少次锁;FutureTask 用它来表现任务的状态(尚未开始、运行、完成和取消) 如JDK的文档中所说,使用AQS来实现一个同步器需要覆盖实现如下几个方法,并且使用 getState , setState , compareAndSetState 这几个方法来设置获取状态 boolean tryAcquire(int arg) boolean tryRelease(int arg) int tryAcquireShared(int arg) boolean

java多线程同步机制AQS解读

↘锁芯ラ 提交于 2020-02-08 02:53:46
java多线程同步机制AQS解读 文章目录 java多线程同步机制AQS解读 一、简介 二、AQS核心知识点 2.1 AQS同步器类定义 2.2 核心实现 2.2.1 FIFO同步队列 2.2.1.1 同步队列解释 2.2.1.2 同步队列源码 2.2.1.3 同步队列安全保证 2.2.2 同步状态 2.2.2.1 同步状态源码 2.2.2.2 同步状态安全保证 2.2.2.3 同步状态使用 2.3 同步实现 2.4 使用方式 三、示例 3.1 调用示例 3.2 调用流程 四、备注 一、简介 AQS(AbstractQueuedSynchronizer,同步器)是java中同步机制的基框架,jdk中的常用同步类如ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore等都是基于AQS同步器实现的,这里结合源码对AQS进行解读,加深对jdk同步类的理解。 二、AQS核心知识点 2.1 AQS同步器类定义 AQS即AbstractQueuedSynchronizer类,是一个抽象类,类定义如下: public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java . io .

AQS抽象队列同步器

青春壹個敷衍的年華 提交于 2020-02-02 03:09:59
AQS AQS:AbstractQqueuedSynchronizer,抽象队列同步器,可以认为是一个模板,提供一个框架,用于实现依赖先进先出(FIFO)等待队列的阻塞锁和相关同步器(信号量,事件等)。 提供了对资源占用、释放,线程的挂起、唤醒的逻辑。 预留了各种try方法给用户实现 可以用在各种需要控制资源争用的场景中。(ReentrantLock/CountDownLatch/Semphore) 使用 1、方法 主要有以下几个方法: acquire(int arg) release(int arg) acquireShared(int arg) releaseShared(int arg) 以上4个方法都是有final修饰的,不可以修改 try开头的4个方法,都会抛出一个异常,留给用户重写 tryAcquire(int arg) tryRelease(int arg) tryAcquireShared(int arg) tryReleaseShared(int arg) 2、字段 int state :同步状态或者说重入次数 Thread owner:占有锁的线程 Queue:阻塞队列 来源: CSDN 作者: 大栗子122 链接: https://blog.csdn.net/weixin_45095479/article/details/104134766

Java并发--Condition的实现分析

陌路散爱 提交于 2020-01-25 02:58:52
Condition的实现分析 ConditionObject是同步器AbstractQueuedSynchronizer的内部类,因为Condition的操作需要获取相关联的锁,所以作为同步器的内部类也较为合理。每个Condition对象都包含着一个队列(以下称为等待队列),该队列是Condition对象实现等待/通知功能的关键。 等待队列 等待队列是一个FIFO的队列 ,在队列中的每个节点都包含了一个线程引用,该线程就是在Condition对象上等待的线程,如果一个线程调用了Condition.await()方法,那么该线程将会释放锁、构造成节点加入等待队列并进入等待状态。事实上, 节点的定义复用了同步器中节点的定义 ,也就是说,同步队列和等待队列中节点类型都是同步器的静态内部类AbstractQueuedSynchronizer.Node。 一个Condition包含一个等待队列,Condition拥有首节点(firstWaiter)和尾节点(lastWaiter)。当前线程调用Condition.await()方法,将会以当前线程构造节点,并将节点从尾部加入等待队列,等待队列的基本结构如下图所示。 如图所示,Condition拥有首尾节点的引用,而新增节点只需要将原有的尾节点nextWaiter指向它,并且更新尾节点即可。上述节点引用更新的过程并没有使用CAS保证

volatile关键字的作用

巧了我就是萌 提交于 2020-01-20 17:45:29
引言   昨日接了一个阿里外包的电话面试,问了一些技术问题感觉到自己是真的菜,接触Java开发已经也有一段时间,技术方面说来惭愧,一直以来只是局限于框架工具的用法,也没有进行了解其实现的原理,更重要的是一直没有归纳和总结,这次把这些问题记录下来,相关的知识点也找了一些资料学习下。 问题 1. CountDownLanch的工作原理 实现原理:计数器的值由构造函数传入,并用它初始化AQS的state值。当线程调用await方法时会检查state的值是否为0,如果是就直接返回(即不会阻塞);如果不是,将表示该节点的线程入列,然后将自身阻塞。当其它线程调用countDown方法会将计数器减1,然后判断计数器的值是否为0,当它为0时,会唤醒队列中的第一个节点,由于CountDownLatch使用了AQS的共享模式,所以第一个节点被唤醒后又会唤醒第二个节点,以此类推,使得所有因await方法阻塞的线程都能被唤醒而继续执行。   引用别人的博客里的一段话,详细请点击: Java并发包中CountDownLatch的工作原理、使用示例 题外话: 什么是 AQS(抽象的队列同步器) AbstractQueuedSynchronizer类如其名,抽象的队列式的同步器,AQS定义了一套多线程访问 共享资源的同步器框架,许多同步类实现都依赖于它,如常用的 ReentrantLock/Semaphore

AQS同步器的实现原理

烈酒焚心 提交于 2020-01-19 00:13:03
1.什么是AQS? AQS的核心思想是基于volatile int state这样的volatile变量,配合Unsafe工具对其原子性的操作来实现对当前锁状态进行修改。同步器内部依赖一个FIFO的双向队列来完成资源获取线程的排队工作。 2.同步器的应用  同步器主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理同步状态,对同步状态的修改或者访问主要通过同步器提供的3个方法: getState() 获取当前的同步状态 setState(int newState) 设置当前同步状态 compareAndSetState(int expect,int update) 使用CAS设置当前状态,该方法能够保证状态设置的原子性。 同步器可以支持独占式的获取同步状态,也可以支持共享式的获取同步状态,这样可以方便实现不同类型的同步组件。 同步器也是实现锁的关键,在锁的实现中聚合同步器,利用同步器实现锁的语义。 3.AQS同步队列 同步器AQS内部的实现是依赖同步队列(一个FIFO的双向队列,其实就是数据结构双向链表)来完成同步状态的管理。 当前线程获取同步状态失败时,同步器AQS会将 当前线程和等待状态 等信息构造成为一个节点(node)加入到同步队列,同时会阻塞当前线程; 当同步状态释放的时候,会把首节点中的线程唤醒,使首节点的线程再次尝试获取同步状态

AQS源码分析

£可爱£侵袭症+ 提交于 2020-01-18 01:08:44
AQS全程为AbstractQueuedSynchronizer,其定义了一套多线程访问共享资源的同步框架,大部分的同步类的实现都依赖于他,比如ReentrantLock,ReentrantReadWriteLock, Semaphore, CountDownLatch等等; AQS的内容包括了以下几个方面: 1) AQS实现线程阻塞和唤醒的基础:LockSupport; 2) AQS子类(自定义同步器); 3) 队列; 4) 独占模式资源请求; 5) 共享模式资源请求; 6) 其他细节; 一、LockSupport: 封装了unsafe的park/unpark接口,提供了阻塞线程和唤醒线程的功能,park/unpark的声明原型为:   public native void unpark(Thread jthread);   public native void park( boolean isAbsolute, long time); isAbsolute参数表示是否是绝对时间,time参数表示时间值,在LockSupport中的实现代码如下: 二、自定义同步器: AQS提供了两种资源共享方式:独占模式和共享模式; AQS提供了同步器的框架代码,需要派生子类来实现自定义同步器,自定义同步器在实现时只需要重载资源请求的接口函数即可

Java并发编程原理 - Unsafe && LockSupport类及AQS同步器的设计

久未见 提交于 2020-01-07 12:49:55
[相关源码] ( https://github.com/Wasabi1234/Java-Concurrency-Progamming-Tutorial ) 1 Unsafe类的park和unpark public native void park(boolean var1, long var2); public native void unpark(Object var1); park方法用来阻塞一个线程,第一个参数用来指示后面的参数是绝对时间还是相对时间,true表示绝对时间,false表示从此刻开始后的相对时间.调用park的线程就阻塞在此处. unpark用来释放某个线程的阻塞,线程用参数var1表示 举个例子: 2 LockSupport 直接使用Unsafe还是有诸多不便之处,因此lock包提供了一个辅助类LockSupport封装了park和unpark 举个例子: 可以看出,使用 LockSupport 要比直接只用 Unsafe 更加便捷。 此外, LockSupport 还可以用来给线程设置一个Blocker对象,便于调试和检测线程,其原理是使用Unsafe的putObject方法直接设置Thread对象的parkBlocker属性,并在合适的时候读取这个Blocker对象,例子如下: 3 AQS同步器 各种锁ReentrantLock