java concurrent 包中的Sync类

原创 2016年08月31日 10:15:18

先看一个这个类的签名:

package java.util.concurrent.locks

public abstract class AbstractQueuedSynchronizer 
extends java.util.concurrent.locks.AbstractOwnableSynchronizer
implements java.io.Serializable

提供一个阻塞锁和相关同步器(信号量,事件等)框架的实现,基于先进先出(FIFO)等待队列。这个类被设计用来为多种同步器提供基础,这些同步器依赖于一个代表状态的单个原子类型的int值。子类必须定义protected方法来改变这个状态,定义的状态意味着这个对象被获取或者释放。除了这些,这个类其他的方法执行所有的入队(queuing )和阻塞(blocking )机制。子类可以维护其他的状态字段,但是考虑到同步,仅仅使用 getState, setState and compareAndSetState操作int值才会自动更新。

子类应该作为一个非public的内部辅助类被定义,实现它们宿主类的同步属性。类AbstractQueuedSynchronizer 不实现任何同步接口,代之的是定义方法例如acquireInterruptibly , 用来构造锁和相关的同步器去实现它们的公共方法。

这个类支持使用单个默认的互斥模式或者共享模式,也可以同时支持这两种模式。当在一个互斥模式中获取成功,其他线程尝试获取就会失败。共享模式被多个线程获取时可能会(但没必要)成功。这个类不“理解”这些区别,除非在手动操作时,当一个共享模式获取成功时,下一个等待的线程(如果存在这样一个线程)必须还得决定它是否也能获取的到。在不同模式下等待的线程共享同样的FIFO队列。通常,实现类只支持这些模式中的一种,但是在像ReadWriteLock这样的例子中,这些模式可以同时起作用。仅支持互斥模式或者共享模式的子类无需定义某些方法来支持那些用不到的模式。

这个类定义了一个内嵌的AbstractQueuedSynchronizer.ConditionObject 类,它作为一个Condition 的实现,被子类用来支持互斥模式,isHeldExclusively 方法报告同步是否互斥地被当前线程所持有,release方法完全释放对象,acquire返回保存的状态值,最终,恢复当前对象到它之前的状态。

AbstractQueuedSynchronizer 中d方的法创建这样一个condition,如果这个限制不能被满足,不要使用它。AbstractQueuedSynchronizer.ConditionObject 行为依赖于它的同步器语义实现的过程。

这个类为内置的队列提供检查,探测和监视方法,以及为condition 条件对象提供相似的方法。这些可以依照要求,作为一个同步语义的AbstractQueuedSynchronizer 被导出到类中。

这个类的序列化仅存储了基础的原子整型来维护状态,这样,反序列化后的对象含有空的线程队列。典型的要求可序列化的子类会定义一个readObject方法,存储这个到一个已知最初的反序列化后的状态。

使用

要使用这个类作为同步器的基础,重定义如下的方法,如果适用的话,通过检查和/或者修改使用getState, setState 和/或 compareAndSetState来同步状态:

tryAcquire
tryRelease
tryAcquireShared
tryReleaseShared
isHeldExclusively

每一个方法默认抛出一个UnsupportedOperationException异常。这些方法的实现,必须是内部线程安全的,以及必须普遍上是短暂的和非阻塞的。使用这个类的唯一途径是定义这些方法。其他所有的方法被定义为final,因为他们不能被单独变化。

你可能也会找到从AbstractOwnableSynchronizer 继承的方法用来跟踪线程,拥有一个互斥同步器。鼓励你使用他们——这个将启用监控和诊断工具在决定那个线程持有锁的时候为用户提供帮助。

即便这个类是基于内部的FIFO队列,他不自动自动强制FIFO获取策略。互斥同步的核心使用如下的形式:

   Acquire:
       while (!tryAcquire(arg)) {
          enqueue thread if it is not already queued;
          possibly block current thread;
       }

   Release:
       if (tryRelease(arg))
          unblock the first queued thread;

(Shared mode is similar but may involve cascading signals.)
Because checks in acquire are invoked before enqueuing, a newly acquiring thread may barge ahead of others that are blocked and queued. However, you can, if desired, define tryAcquire and/or tryAcquireShared to disable barging by internally invoking one or more of the inspection methods, thereby providing a fair FIFO acquisition order. In particular, most fair synchronizers can define tryAcquire to return false if hasQueuedPredecessors (a method specifically designed to be used by fair synchronizers) returns true. Other variations are possible.

对于默认策略(也叫做成贪婪,弃权和护送避免),吞吐量和可扩展性通常是最高的。然而不保证是公平或者无饥饿的,更早入队的线程被允许在后续在队的线程之前重新竞争,每一次重新竞争有一个公正的机会来赢过到来的线程。而且,acquires 在多数的场景中不“自旋”,他们可能在阻塞之前使用其他计算执行多个tryAcquire的调用。
This gives most of the benefits of spins when exclusive synchronization is only briefly held, without most of the liabilities when it isn’t. If so desired, you can augment this by preceding calls to acquire methods with “fast-path” checks, possibly prechecking hasContended and/or hasQueuedThreads to only do so if the synchronizer is likely not to be contended

这个类通过特殊化它的同步器使用范围,依赖于int型的状态,获取和释放参数,以及一个内置的FIFO等待队列,在某种程度上为同步提供了一个有效和可扩展的基础。当这个不够用的时候,你可以由一个使用原子类的底层次构建一个同步器。你拥有自定义的java.util.Queue 类,和LockSupport 阻塞支持。

使用示例

这里有一个不可重入的互斥锁类,它使用值0代表解锁状态,1代表加锁状态。当一个不可重入锁不严格要求当前属主线程做记录,这个类仍然会做,使得监控变的简单。它还支持条件,暴漏这其中的一个探测方法:

 class Mutex implements Lock, java.io.Serializable {
    // Our internal helper class
    private static class Sync extends AbstractQueuedSynchronizer {
      // Reports whether in locked state
      protected boolean isHeldExclusively() {
        return getState() == 1;
      }

      // Acquires the lock if state is zero
      public boolean tryAcquire(int acquires) {
        assert acquires == 1; // Otherwise unused
        if (compareAndSetState(0, 1)) {
          setExclusiveOwnerThread(Thread.currentThread());
          return true;
        }
        return false;
      }

      // Releases the lock by setting state to zero
      protected boolean tryRelease(int releases) {
        assert releases == 1; // Otherwise unused
        if (getState() == 0) throw new IllegalMonitorStateException();
        setExclusiveOwnerThread(null);
        setState(0);
        return true;
      }

      // Provides a Condition
      Condition newCondition() { return new ConditionObject(); }

      // Deserializes properly
      private void readObject(ObjectInputStream s)
          throws IOException, ClassNotFoundException {
        s.defaultReadObject();
        setState(0); // reset to unlocked state
      }
    }

    // The sync object does all the hard work. We just forward to it.
    private final Sync sync = new Sync();

    public void lock()                { sync.acquire(1); }
    public boolean tryLock()          { return sync.tryAcquire(1); }
    public void unlock()              { sync.release(1); }
    public Condition newCondition()   { return sync.newCondition(); }
    public boolean isLocked()         { return sync.isHeldExclusively(); }
    public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
    public void lockInterruptibly() throws InterruptedException {
      sync.acquireInterruptibly(1);
    }
    public boolean tryLock(long timeout, TimeUnit unit)
        throws InterruptedException {
      return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
  }

这里是一个类似于CountDownLatch的闭锁类,除了它仅仅要求触发一个单独的信号。因为一个闭锁是非互斥的,它使用共享的acquire和release方法。

   class BooleanLatch {

    private static class Sync extends AbstractQueuedSynchronizer {
      boolean isSignalled() { return getState() != 0; }

      protected int tryAcquireShared(int ignore) {
        return isSignalled() ? 1 : -1;
      }

      protected boolean tryReleaseShared(int ignore) {
        setState(1);
        return true;
      }
    }

    private final Sync sync = new Sync();
    public boolean isSignalled() { return sync.isSignalled(); }
    public void signal()         { sync.releaseShared(1); }
    public void await() throws InterruptedException {
      sync.acquireSharedInterruptibly(1);
    }
  }
版权声明:本文为博主原创文章,未经博主允许不得转载。

Java同步工具类总结

本文可作为传智播客《张孝祥-Java多线程与并发库高级应用》的学习笔记。 Semaphore 这个东西和之前的synchronized干的事差不多。 synchronized保证了,我管理的那部分代...

java.util.concurrent.atomic原子操作类包

这个包里面提供了一组原子变量类。其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋...

java.concurrent包常见类详解

一、线程安全的集合类 1、CopyOnWriteArrayList ArrayList的一个线程安全的实体。其中所有可变操作都是通过对底层数组经常一次新的复制来实现的。 比如add(E)时,容器自动c...

Java.util.concurrent包学习(二)线程同步控制相关的类 (

Java.util.concurrent包学习(二)线程同步控制相关的类  (2013-11-12 10:22:44) 转载▼ 标签:  java学习 分...

java concurrent 包 详细解析

  • 2012年03月14日 15:41
  • 3.22MB
  • 下载

java.concurrent包的应用

  • 2009年11月24日 16:44
  • 42KB
  • 下载

谈谈java.util.concurrent包的并发处理(转)

浅谈java.util.concurrent包的并发处理(转) 我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常需要有程序员独立完成代码实现,而当针对高质量Java多线程...

java concurrent包分类结构图

  • 2016年12月21日 16:14
  • 91KB
  • 下载

java concurrent包自带线程池和队列详细讲解

Java线程池使用说明一简介线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的。在jdk1.5之后这一情况有了很大的改观。Jdk1.5之后加入...
  • jethai
  • jethai
  • 2016年08月28日 14:02
  • 887

时间久了再温习一下Java concurrent包

1、阻塞队列BlockingQueue(重点掌握) 阻塞队列是表示线程插入与移除的队列,常用的有几个实现类( ArrayBlockingQueue, LinkedBlockQueue Priority...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java concurrent 包中的Sync类
举报原因:
原因补充:

(最多只允许输入30个字)