文档章节

Java中的锁使用与实现

ZH-JSON
 ZH-JSON
发布于 06/22 09:28
字数 2311
阅读 12
收藏 0
点赞 0
评论 0
  1. Lock接口 锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源。 在Lock出现之前,java程序是靠synchronized关键字实现锁功能的,而Java SE5之后,并发包中新增了Lock接口用来实现锁功能。它提供了与synchronized关键字类似的同步功能,只是在使用时需要显示地获取和释放锁。有用了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等synchronized关键字所不具备的同步特性。

    Lock接口提供的synchronized关键字所不具备的主要特性       1).尝试非阻塞地获取锁。       2).能被中断的获取锁。获取到锁的线程能够响应中断,当获取到锁的线程被中断,当获取到锁的线程被中断时,中断异常将会被抛出,同时锁会释放。       3).超时获取锁 在指定的时间之前获取锁,如果截止时间到了仍旧无法获取锁,则返回。 Lock是一个接口,它定义了锁获取和释放的基本操作。 void lock() 获取锁,调用该方法当前线程将会获取锁,当锁获取后,从改方法返回。 void lockInterruptibly() 可中断的获取锁,和lock()方法的不同之处在于该方法会响应中断,即在锁的获取中可中断当前线程。 boolean tryLock() 尝试返回非阻塞获取锁,调用该方法后立即返回,如果能够获得返回true,否则返回flase。 boolean tryLock(long time,TimeUnit unit) 超时的获取锁,当前线程在以下3种情况下会返回:1.当前线程在超时时间内获得了锁 2.当前线程在超时时间内被中断 3.超时时间结束,返回false. void unlock() 释放锁 Condition newCondition() 获取等待通知组件,该组件和当前的锁绑定,当前线程只有获得了锁,才能调用该组件的wait()方法,当调用后,当前线程将锁释放。

2.   AQS队列同步器AbstractQueuedSynchronizer,用来构建锁或者其他同步组建的基础框架。用一个int类型的state成员变量表示同步状态,通过内置的FIFO 队列来完成资源获取线程的排队工作。 同步器的主要使用方法是继承,子类通过继承同步器(AQS)并实现它的抽象方法来管理同步状态,在抽象方法的实现过程中免不了进行状态更改。需要同步器提供三个方法getState(),setState()和compareAndSetState()来进行操作,因为他们能够保证状态的改变是安全的。子类推荐被定义为自定义同步组件的静态内部类,同步器自身没有实现任何同步接口。它仅仅是定义了若干同步状态获取和释放的方法来提供同步组件使用。 同步器既可以支持独占式地获取同步状态,也可以支持共享地获取同步状态。这样可以实现不同类型的同步组件(ReentrantLock、ReentrantReadWriteLock和CountDownLatch等)。 队列同步器的接口与示例 同步器的设计是基于模板方法的,也就是说,使用者需要继承同步器并重新指定的方法,随后将同步器组合在自定义同步组件的实现中,并调用同步器提供的模板方法,而这些模板方法将会调用使用者重写的方法。 重写同步器指定的方法时,需要使用同步器提供的如下3个方法来访问或者修改同步状态。 a) getState() b) setState(int newState) 设置当前同步状态 c) compareAndSetState(int except,int update):使用CAS设置当前状态,改方法能够保证状态设置的原子性。

同步器可重写的方法与描述 boolean tryAcquire(int arg) 独占式获取同步状态 boolean tryRelease(int arg) 独占式释放同步状态 int tryAcquireShared(int arg) 共享式获取同步状态 boolean tryReleaseShared(int arg) 共享式释放同步状态 boolean isHeldExcusively() 当前同步器是否在独占模式下被线程占用,一般该方法表示是否被当前线程所独占。

实现自定义同步组件时,将会提供同步器提供的模板方法,这些模板方法描述如下 void acquire(int arg) 独占式获取同步状态,如果当前线程获取同步状态成功,则由改方法返回,否则,进入同步队列等待。 void acquireInterruptibly(int arg) 与acquire(int arg)相同,但是该方法响应中断。 boolean tryAcquireNanos(int arg,long nanos) 在anquireInterruptibly(int arg)基础上增加了超时限制

void acquireShared(int arg) 共享获取同步状态,如果当前线程获取同步状态成功,则由改方法返回,否则,进入同步队列等待。 void acquireSharedInterruptibly(int arg) 与acquireShared(int arg)相同,但是该方法响应中断。 boolean tryAcquireSharedNanos(int arg,long nanos) 在 anquireSharedInterruptibly(int arg)基础上增加了超时限制 boolean release(int arg)独占式的释放同步状态,该方法会在释放同步状态之后,将同步队列中的第一个节点中包含的线程唤醒。 boolean releaseShared(int arg) 共享式的释放同步状态 Collection<Thread> getQueuedThreads() 获取等待队列上的线程集合

同步器提供的模板方法基本分为三类:独占模式获取与释放同步状态、共享式获取与释放同步状态和查询同步队列的等待线程情况。

class Mutex implments Lock { private static class Sync extends AbstractQueuedSynchronizer { //是否处于占用状态 protected boolean isHeldExclusively{ return getState()==1 } //当前状态为0的时候获取锁 public boolean tryAcquire(int acquires){ if(compareAndSwap(0,1)){ setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } //释放锁,将状态设置为0 protected boolean tryRelease(int release){ if(getState()==0) throw new IllegalMonitorStateException(); setState(0); setExclusiveOwnerThread(null); return true; } //返回一个Condition 每个Condition都包含一个condition状态 Condition newCondition(){ return new ConditionObject(); } }

//仅需要将操作代理到Sunc上即可,使用模板方法 private final Sync sync=new Sync(); public void lock(){ sync.lock(); } public boolean tryLock(){ return sync.tryLock(); } ..... } 在Mutex中定义一个静态内部类,该内部类继承了同步器并实现了独占模式获取和释放同步状态。在tryAcquire(int acquires)方法中,如果经过CAS设置成功(设置同步状态为1),则代表获取了同步状态,而在tryRelease(int release)方法中只是将同步状态设置为0.用户使用Mutex时并不会直接和内部同步器的实现打交道,而是调用Mutex提供的方法,在Mutex的实现中,以获取锁的lock()方法为例,只需在方式实现中调用同步器的模板方法acquire(int args)即可。

队列同步器的实现分析

1.同步队列 同步器依赖内部的同步队列(一个FIFO双向队列)来完成同步状态的管理,当前线程获取同步状态失败后时,同步器将会将当前线程以及等待状态等信息构造成为一个节点(Node)并将其加入同步队列,同时阻塞当前线程,当同步状态释放时,会把首节点中的线程唤醒,再次尝试获取同步状态。 2.独占式同步状态获取与释放 通过调用acquire(int arg)方法获取同步状态,该方法对中断不敏感,进入同步队列中,线程被中断后,线程不会从同步队列中移除。

3.共享式同步获取与释放 共享式获取与独占式获取最主要的区别在于同一时刻能否有多个线程同时获取同步状态。

4.独占式超时获取同步状态 通过调用同步器的doAcquireNanos(int arg,long nanosTimeout)方法可以超时获得同步状态,即在指定的时间段内获取同步状态。如果获取到同步状态返回tue,否则返回false. 响应中断的同步状态获取过程。在Java5之前,当一个线程获取不到锁而被阻塞在synchronizer之外时,对线程进行中断操作,此时改线程的中断标志位被修改,但是线程依旧会阻塞在synchronized上,等待着获取锁。在Java5中,同步器提供了acquireInterruptibly(int arg)方法,这个方法在等待获取同步锁状态时,如果当前线程被中断,会立即返回,并抛出InterruptException。 超时获取同步状态可以被视为响应中断获取同步状态过程的“增强版”,doAcquireNanos(int arg,long nanosTimeOut)方法在支持响应中断的基础上,增加了超时获取的特性。

© 著作权归作者所有

共有 人打赏支持
ZH-JSON
粉丝 0
博文 20
码字总数 18668
作品 0
浦东
高级程序员
Java SE1.6中的Synchronized

1 引言 在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本文详细介绍了J...

serenity
2015/07/15
0
0
聊聊并发(二)Java SE1.6中的Synchronized

在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本文详细介绍了Java SE1....

陶邦仁
2015/03/18
0
0
Java SE1.6中的Synchronized详解

1 引言 在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本文详细介绍了J...

闵开慧
2013/08/06
0
0
CAS原理 Java SE1.6中的Synchronized

在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁(后面的章节还会谈到锁)。 锁机制存在以下问题: (1)在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延...

指尖的舞者
2014/04/23
0
0
JAVA多线程和并发基础面试问答

原文链接 译文连接 作者:Pankaj 译者:郑旭东 校对:方腾飞 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一。在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢...

雷神雨石
2014/07/19
0
2
JAVA多线程和并发基础面试问答

多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一。在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌握Java多线程基础知识来对应日后碰到的问题。(校对注:...

LCZ777
2014/05/26
0
0
Java SE 6 新特性: JMX 与系统管理

Java SE 6 新特性: JMX 与系统管理 2006 年底,Sun 公司发布了 Java Standard Edition 6(Java SE 6)的最终正式版,代号 Mustang(野马)。跟 Tiger(Java SE 5)相比,Mustang 在性能方面有...

ihaolin
2014/08/07
0
0
【转】Java线程面试题Top50

目录(?)[-] 50道Java线程面试题 1 什么是线程 2 线程和进程有什么区别 3 如何在Java中实现线程 4 用Runnable还是Thread 6 Thread 类中的start 和 run 方法有什么区别 7 Java中Runnable和Cal...

gehui
2015/08/14
0
0
JAVA多线程和并发基础面试问答

Java多线程面试问题 1. 进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用。而线程是在进程中执行的一个任务。Java运行环境是一...

清风傲剑
2014/12/06
0
0
【转】15个顶级Java多线程面试题及回答

Java 线程面试问题   在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分。如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题。在投资银行业务...

一只死笨死笨的猪
2014/09/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

MyBatis源码解读之延迟加载

1. 目的 本文主要解读MyBatis 延迟加载实现 2. 延迟加载如何使用 Setting 参数配置 设置参数 描述 有效值 默认值 lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加...

无忌
3分钟前
0
0
javascript 类变量的实现

代码如下: function echo(){ for(let i=0;i<arguments.length;i++) console.log(arguments[i]);}function extend(o, p){for (prop in p) {o[prop] = p[prop]}retur......

backbye
7分钟前
0
1
编程语言对比分析:Python与Java和JavaScript(图)

编程语言对比分析:Python与Java和JavaScript(图): 凭什么说“Python 太慢,Java 太笨拙,我讨厌 JavaScript”?[图] 编程语言生而为何? 我们人类从原始社会就是用语言表达自己,互相沟通...

原创小博客
15分钟前
0
0
Akka构建Reactive应用《one》

看到这Akka的官网,描述使用java或者scala构建响应式,并发和分布式应用更加简单,听着很高级的样子,下面的小字写着消息驱动,但是在quickstart里面又写容错事件驱动,就是这么钻牛角尖。 ...

woshixin
27分钟前
0
0
ffmpeg源码分析 (四)

io_open 承接上一篇,对于avformat_open_input的分析还差其中非常重要的一步,就是io_open,该函数用于打开FFmpeg的输入输出文件。 在init_input中有这么一句 if ((ret = s->io_open(s, &s-...

街角的小丑
28分钟前
0
0
String,StringBuffer ,StringBuilder的区别

不同点 一、基类不同 StringBuffer、StringBuilder 都继承自AbStractStringBuilder,String 直接继承自 Object 2、底层容器“不同” 虽然底层都是字符数组,但是String的是final修饰的不可变...

不开心的时候不要学习
43分钟前
0
0
nodejs 文件操作

写文件code // 加载文件模块var fs = require("fs");var content = 'Hello World, 你好世界!';//params 文件名,内容,编码,回调fs.writeFile('./hello.txt',content,'utf8',function (er......

yanhl
46分钟前
0
0
SpringBoot mybits 查询为0条数据 但是在Navicat 中可以查询到数据

1.页面请求: 数据库查询: 2018-07-16 17:56:25.054 DEBUG 17312 --- [nio-9010-exec-3] c.s.h.m.C.selectSelective : ==> Preparing: select id, card_number, customer_id, customer_nam......

kuchawyz
56分钟前
0
0
译:Self-Modifying cod 和cacheflush

date: 2014-11-26 09:53 翻译自: http://community.arm.com/groups/processors/blog/2010/02/17/caches-and-self-modifying-code Cache处在CPU核心与内存存储器之间,它给我们的感觉是,它具......

我叫半桶水
58分钟前
0
0
Artificial Intelligence Yourself

TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理。Tensor(张量)意味着N维数组,Flow(流)意味着基于数据流图的计算,TensorFlow为张量从流...

孟飞阳
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部