`

java AbstractQueuedSynchronizer介绍以及原理分析

 
阅读更多
简介
提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架。
该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础。使用的方法是继承,子类通过继承同步器并需要实现它的方法来管理其状态,管理的方式就是通过类似acquire和release的方式来操纵状态。然而多线程环境中对状态的操纵必须确保原子性,因此子类对于状态的把握,需要使用这个同步器提供的以下三个方法对状态进行操作:

java.util.concurrent.locks.AbstractQueuedSynchronizer.getState()
java.util.concurrent.locks.AbstractQueuedSynchronizer.setState(int)
java.util.concurrent.locks.AbstractQueuedSynchronizer.compareAndSetState(int, int)


子类推荐被定义为自定义同步装置的内部类,同步器自身没有实现任何同步接口,它仅仅是定义了若干acquire之类的方法来供使用。该同步器即可以作为排他模式也可以作为共享模式,当它被定义为一个排他模式时,其他线程对其的获取就被阻止,而共享模式对于多个线程获取都可以成功。

同步器是实现锁的关键,利用同步器将锁的语义实现,然后在锁的实现中聚合同步器。可以这样理解:锁的API是面向使用者的,它定义了与锁交互的公共行为,而每个锁需要完成特定的操作也是透过这些行为来完成的(比如:可以允许两个线程进行加锁,排除两个以上的线程),但是实现是依托给同步器来完成;同步器面向的是线程访问和资源控制,它定义了线程对资源是否能够获取以及线程的排队等操作。锁和同步器很好的隔离了二者所需要关注的领域,严格意义上讲,同步器可以适用于除了锁以外的其他同步设施上(包括锁)。
同步器的开始提到了其实现依赖于一个FIFO队列,那么队列中的元素Node就是保存着线程引用和线程状态的容器,每个线程对同步器的访问,都可以看做是队列中的一个节点。Node的主要包含以下成员变量:


Node {

    int waitStatus;

    Node prev;

    Node next;

    Node nextWaiter;

    Thread thread;

}

以上五个成员变量主要负责保存该节点的线程引用,同步等待队列(以下简称sync队列)的前驱和后继节点,同时也包括了同步状态。



节点成为sync队列和condition队列构建的基础,在同步器中就包含了sync队列。同步器拥有三个成员变量:sync队列的头结点head、sync队列的尾节点tail和状态state。对于锁的获取,请求形成节点,将其挂载在尾部,而锁资源的转移(释放再获取)是从头部开始向后进行。对于同步器维护的状态state,多个线程对其的获取将会产生一个链式的结构。

一个例子
在上述对同步器AbstractQueuedSynchronizer进行了实现层面的分析之后,我们通过一个例子来加深对同步器的理解:
设计一个同步工具,该工具在同一时刻,只能有两个线程能够并行访问,超过限制的其他线程进入阻塞状态。
对于这个需求,可以利用同步器完成一个这样的设定,定义一个初始状态,为2,一个线程进行获取那么减1,一个线程释放那么加1,状态正确的范围在[0,1,2]三个之间,当在0时,代表再有新的线程对资源进行获取时只能进入阻塞状态(注意在任何时候进行状态变更的时候均需要以CAS作为原子性保障)。由于资源的数量多于1个,同时可以有两个线程占有资源,因此需要实现tryAcquireShared和tryReleaseShared方法,这里谢谢luoyuyou和同事小明指正,已经修改了实现。

public class TwinsLock implements Lock {
	private final Sync	sync	= new Sync(2);

	private static final class Sync extends AbstractQueuedSynchronizer {
		private static final long	serialVersionUID	= -7889272986162341211L;

		Sync(int count) {
			if (count <= 0) {
				throw new IllegalArgumentException("count must large than zero.");
			}
			setState(count);
		}

		public int tryAcquireShared(int reduceCount) {
			for (;;) {
				int current = getState();
				int newCount = current - reduceCount;
				if (newCount < 0 || compareAndSetState(current, newCount)) {
					return newCount;
				}
			}
		}

		public boolean tryReleaseShared(int returnCount) {
			for (;;) {
				int current = getState();
				int newCount = current + returnCount;
				if (compareAndSetState(current, newCount)) {
					return true;
				}
			}
		}
	}

	public void lock() {
		sync.acquireShared(1);
	}

	public void lockInterruptibly() throws InterruptedException {
		sync.acquireSharedInterruptibly(1);
	}

	public boolean tryLock() {
		return sync.tryAcquireShared(1) >= 0;
	}

	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		return sync.tryAcquireSharedNanos(1, unit.toNanos(time));
	}

	public void unlock() {
		sync.releaseShared(1);
	}

	@Override
	public Condition newCondition() {
		return null;
	}
}


测试

public class TwinsLockTest {

	@Test
	public void test() {
		final Lock lock = new TwinsLock();

		class Worker extends Thread {
			public void run() {
				while (true) {
					lock.lock();

					try {
						Thread.sleep(1000L);
				System.out.println(Thread.currentThread());
						Thread.sleep(1000L);
					} catch (Exception ex) {

					} finally {
						lock.unlock();
					}
				}
			}
		}

		for (int i = 0; i &lt; 10; i++) {
			Worker w = new Worker();
			w.start();
		}

		new Thread() {
			public void run() {
				while (true) {

					try {
						Thread.sleep(200L);
						System.out.println();
					} catch (Exception ex) {

					}
				}
			}
		}.start();

		try {
			Thread.sleep(20000L);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

转自:http://ifeve.com/introduce-abstractqueuedsynchronizer/
  • 大小: 24.4 KB
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    Java并发系列之AbstractQueuedSynchronizer源码分析(独占模式)

    【Java并发系列之AbstractQueuedSynchronizer源码分析(独占模式)】 AbstractQueuedSynchronizer(AQS)是Java并发编程中一个重要的工具,它是Java并发包`java.util.concurrent.locks`中的核心抽象类,用于构建锁...

    java并发编程艺术

    3. **并发工具类**:介绍Java并发包(java.util.concurrent)中的各种工具类,如Semaphore信号量、CountDownLatch倒计时器、CyclicBarrier回环栅栏、ThreadPoolExecutor线程池等,以及如何在实际编程中合理使用它们...

    Java并发包源码分析(JDK1.8)

    Java并发包源码分析(JDK1.8):囊括了java.util.concurrent包中大部分类的源码分析,其中涉及automic包,locks包(AbstractQueuedSynchronizer、ReentrantLock、ReentrantReadWriteLock、LockSupport等),queue...

    3.1.4.AQS底层原理分析1

    【3.1.4.AQS底层原理分析1】 在Java并发编程中,AbstractQueuedSynchronizer(AQS)是一个核心的同步组件,用于构建锁和同步器的基础框架。AQS是一个抽象类,它提供了线程同步的基本机制,包括线程的排队、等待和...

    java技术指南

    文档内容丰富,既包括了Java的基本语法、源码分析、多线程处理、IO流操作、设计模式、常用框架、数据库技术、数据结构与算法、JVM原理、Web开发技术,也包括了Linux操作系统、Redis数据库、UML绘图以及JDK的新特性等...

    JAVA程序员面试大全(包括笔试和面试)

    还要掌握如何通过JVM参数调整内存配置,以及如何分析和解决内存泄漏问题。 面向对象设计原则和设计模式是面试中的高级话题。如单一职责原则、开闭原则、里氏替换原则、依赖倒置原则等,以及常见的设计模式,如工厂...

    Java分布式应用学习笔记06浅谈并发加锁机制分析

    下面我们将深入分析`ReentrantLock`的工作原理。 #### 3. 轻量级锁`ReentrantLock` `ReentrantLock`是一种可重入的互斥锁,支持公平和非公平两种模式。它内部有一个`Sync`类,继承自`AbstractQueuedSynchronizer`...

    java锁机制基类AbstractQueuedSynchronizer从设计到实现到应用

    从并发概念、场景分析出发,依次引出锁、等待队列等概念,直至分析清楚java锁机制实现的原理。...最后介绍了AbstractQueuedSynchronizer的应用,即如何用它来实现并发控制,以及如何自定义并发组件。

    基于JDK源码解析Java领域中的并发锁之设计与实现.pdf

    在Java并发编程中,理解和掌握并发锁的原理与实现至关重要,因为它们是解决多线程环境下的互斥和同步问题的关键。本文将基于JDK源码解析Java领域中的并发锁,探讨AQS基础同步器、LockSupport、Condition接口、Lock...

    JAVA面试题2019

    11. **AQS框架**:`AbstractQueuedSynchronizer`框架的基础原理,如等待队列和独占模式等。 12. **死锁检测与预防**:如何检测死锁以及常用的预防死锁的方法。 ### Spring框架 #### 关键知识点: 1. **依赖注入**...

    Java高级工程师简历模板18k+

    3. **JVM深入理解**:对Java虚拟机(JVM)、Java内存模型(JMM)、垃圾收集(GC)机制、GC算法、JVM配置参数有深入了解,熟悉classLoader、锁机制,并能够使用如jmap、jstack、java visualVM等工具进行故障分析和...

    并发编程以及计算机底层原理

    6. **阻塞队列BlockingQueue**:`14-阻塞队列BlockingQueue实战及其原理分析二-fox`讲解了阻塞队列的概念。 BlockingQueue是一种特殊的队列,当队列满时,生产者线程会被阻塞;队列空时,消费者线程会被阻塞。这种...

    Java并发 结合源码分析AQS原理

    Java并发结合源码分析AQS原理 Java并发编程中,AQS(AbstractQueuedSynchronizer)是一个核心组件,它提供了一个基于FIFO队列和状态变量的基础框架,用于构建锁和其他同步装置。在这篇文章中,我们将深入探讨AQS的...

    java面试精选必备题集

    * ThreadLocal原理分析 + 线程局部变量 * 线程池的实现原理 + 批量执行任务 * 线程池的几种实现方式 + CachedThreadPool + FixedThreadPool + ScheduledThreadPool 四、锁机制 1.4 锁机制 * 线程安全问题,...

    Java后端技术面试基础汇总

    - **AQS(AbstractQueuedSynchronizer)**:提供了一种构造锁和同步器的框架。 - **CAS(Compare and Swap)**:无锁编程技术,用于实现乐观锁。 - **乐观锁和悲观锁**:乐观锁假设竞争不激烈,悲观锁总是假设最...

    3.1.5.并发工具的使用以及原理1

    "Java 并发工具 Condition 的使用和原理" Condition 是 Java 中一个多线程协调通信的工具类,通过它可以实现对线程的通信。Condition 的基本使用可以分为两种,一种是 ConditionWait,另一种是 ConditionSignal。 ...

    Java多线程与并发-原理

    本文将深入探讨`synchronized`的工作原理、实现机制以及与其他并发工具的对比。 **synchronized线程安全** 线程安全是多线程编程中的一个核心概念,它指的是当多个线程同时访问一个对象时,该对象的状态不会被破坏...

    Java后端技术面试汇总-2019

    - **ThreadLocal原理分析**:通过ThreadLocalMap实现线程局部变量的隔离。 - **线程池的实现原理**:维护一组工作线程,根据任务队列调度任务。 - **线程池的几种实现方式**:FixedThreadPool、CachedThreadPool等...

    互联网大厂Java高级工程师岗位面试真题154道

    Java集合框架是Java程序员必须掌握的重要内容,它包括List、Set、Map等接口以及ArrayList、LinkedList、HashMap等具体实现。面试中常常考察这些概念的区别和特性。 1. ArrayList和Vector的主要区别在于线程安全和...

    JDK_AIP1.7源码.rar

    在给定的压缩包“JDK_AIP1.7源码.rar”中,我们主要关注的是JDK 1.7版本的源代码,这对于理解Java语言的工作原理、深入学习Java API以及进行高级编程和性能优化至关重要。 1. **Java虚拟机(JVM)** - JVM是Java...

Global site tag (gtag.js) - Google Analytics