在Java多线程编程中,我们经常使用synchronized关键字来实现同步,控制多线程对变量的访问,来避免并发问题。

但是有的时候,synchronized关键字会显得过于沉重,不够灵活。synchronized 方法或语句的使用提供了对与每个对象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在一个块结构中:当获取了多个锁时,它们必须以相反的顺序释放,且必须在与所有锁被获取时相同的词法范围内释放所有锁。

这个时候Lock出现。

Lock不是Java中的关键字而是 java.util.concurrent.locks 包中的一个接口。下面我们简单介绍一下Lock接口。

一、Lock接口简介

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。

Lock相对于synchronized关键字而言更加灵活,你可以自由得选择我你想要加锁的地方。当然更高的自由度也带来更多的责任。

我们通常会在try...catch模块中使用lock关键字,在finally模块中释放锁。下面是示范代码。

    Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}

锁的锁定和释放如果在不同的模块时,需要谨慎编码,确保最后锁一定能够得到释放。

二、Lock接口中定义的方法

1、void lock()
获取锁。如果锁不可用,出于线程调度目的,将禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态

2、void lockInterruptibly()
如果当前线程未被中断,则获取锁。

3、Condition newCondition()
返回绑定到此 Lock 实例的新 Condition 实例。

4、boolean tryLock()
仅在调用时锁为空闲状态才获取该锁。如果锁可用,则获取锁,并立即返回值 true。如果锁不可用,则此方法将立即返回值 false

5、boolean tryLock(long time, TimeUnit unit)
如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。

6、void unlock()
释放锁。在等待条件前,锁必须由当前线程保持。调用 Condition.await() 将在等待前以原子方式释放锁,并在等待返回前重新获取锁。

三、实现类ReentrantLock

Lock接口有三个实现类分别是ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock。后面两个是内部类。

第一个ReentrantLock,在我们平常使用中更为频繁。

ReentrantLock是一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。

ReentrantLock的构造方法接受一个可选的公平 参数。当设置为 true 时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。也就是说这里可以设置锁的类型为公平锁还是非公平锁。但是,需要注意的是公平锁的情况下,也不能完全确保公平,它总是趋向公平的情况。

ReentrantLock类中还定义了Lock接口之外的方法,例如int getHoldCount() 、boolean hasQueuedThreads() 、boolean hasWaiters(Condition condition)等等,这些方法可以查询当前锁的状态。

四、代码使用

package com.test;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class TestLock { public static void main(String[] args) {
Lock lock = new ReentrantLock();
for(int i=0;i<5;i++){
ThreadPrintStar threadPrintStar = new TestLock().new ThreadPrintStar(lock);
threadPrintStar.start();
}
} /**
* 打印星星
* @author LKB
*
*/
class ThreadPrintStar extends Thread{
private Lock lock; public ThreadPrintStar(Lock lock) {
// TODO Auto-generated constructor stub
this.lock = lock;
} public void run(){
lock.lock();
try {
for(int i=0;i<5;i++){
if(i%2 == 0)
System.out.println("i = " + i + "+++" + Thread.currentThread().getName() +
" print: " + "☆☆");
else
System.out.println("i = " + i + "+++" + Thread.currentThread().getName() +
" print: " + "★★"); }
System.out.println();
System.out.println();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally {
lock.unlock();
}
}
} }

下面是程序运行结果,可以看到我们通过Lock实现了同步。

i = 0+++Thread-0 print: ☆☆
i = 1+++Thread-0 print: ★★
i = 2+++Thread-0 print: ☆☆
i = 3+++Thread-0 print: ★★
i = 4+++Thread-0 print: ☆☆ i = 0+++Thread-1 print: ☆☆
i = 1+++Thread-1 print: ★★
i = 2+++Thread-1 print: ☆☆
i = 3+++Thread-1 print: ★★
i = 4+++Thread-1 print: ☆☆ i = 0+++Thread-2 print: ☆☆
i = 1+++Thread-2 print: ★★
i = 2+++Thread-2 print: ☆☆
i = 3+++Thread-2 print: ★★
i = 4+++Thread-2 print: ☆☆ i = 0+++Thread-4 print: ☆☆
i = 1+++Thread-4 print: ★★
i = 2+++Thread-4 print: ☆☆
i = 3+++Thread-4 print: ★★
i = 4+++Thread-4 print: ☆☆ i = 0+++Thread-3 print: ☆☆
i = 1+++Thread-3 print: ★★
i = 2+++Thread-3 print: ☆☆
i = 3+++Thread-3 print: ★★
i = 4+++Thread-3 print: ☆☆

Lock接口简介的更多相关文章

  1. java多线程Lock接口简介使用与synchronized对比 多线程下篇(三)

    前面的介绍中,对于显式锁的概念进行了简单介绍 显式锁的概念,是基于JDK层面的实现,是接口,通过这个接口可以实现同步访问 而不同于synchronized关键字,他是Java的内置特性,是基于JVM的 ...

  2. Java基础知识强化之多线程笔记06:Lock接口 (区别于Synchronized块)

    1. 简介 我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java 5之后,在java.util.concurrent.locks包下提供了另外一种方式 ...

  3. SQLite3 C/C++ 开发接口简介

    SQLite3 C/C++ 开发接口简介 1.0 总览 SQLite3是SQLite一个全新的版本,它虽然是在SQLite 2.8.13的代码基础之上开发的,但是使用了和之前的版本不兼容的数据库格式和 ...

  4. 显式锁(二)Lock接口与显示锁介绍

    一.显式锁简介    显式锁,这个叫法是相对于隐式锁synchronized而言的,加锁和解锁都要用户显式地控制.显示锁Lock是在Java5中添加到jdk的,同synchronized一样,这也是一 ...

  5. synchronized关键字,Lock接口以及可重入锁ReentrantLock

    多线程环境下,必须考虑线程同步的问题,这是因为多个线程同时访问变量或者资源时会有线程争用,比如A线程读取了一个变量,B线程也读取了这个变量,然后他们同时对这个变量做了修改,写回到内存中,由于是同时做修 ...

  6. 线程同步 Lock接口

    同步:★★★★★ 好处:解决了线程安全问题. 弊端:相对降低性能,因为判断锁需要消耗资源,产生了死锁. 定义同步是有前提的: 1,必须要有两个或者两个以上的线程,才需要同步. 2,多个线程必须保证使用 ...

  7. Java多线程(五) Lock接口,ReentranctLock,ReentrantReadWriteLock

    在JDK5里面,提供了一个Lock接口.该接口通过底层框架的形式为设计更面向对象.可更加细粒度控制线程代码.更灵活控制线程通信提供了基础.实现Lock接口且使用得比较多的是可重入锁(Reentrant ...

  8. jdk1.5多线程Lock接口及Condition接口

    jdk1.5多线程的实现的方式: jdk1.5之前对锁的操作是隐式的 synchronized(对象) //获取锁 { } //释放锁 jdk1.5锁的操作是显示的:在包java.util.concu ...

  9. Linux中的IO复用接口简介(文件监视?)

    I/O复用是Linux中的I/O模型之一.所谓I/O复用,指的是进程预先告诉内核,使得内核一旦发现进程指定的一个或多个I/O条件就绪,就通知进程进行处理,从而不会在单个I/O上导致阻塞. 在Linux ...

随机推荐

  1. Ubuntu 火狐浏览器中,鼠标选择文字被删除的解决办法

    copy from :http://blog.csdn.net/shadow066/article/details/50628019 在终端中输入命令:ibus-setup 将 “在应用程序窗口中启用 ...

  2. python---twisted的使用,使用其模拟Scrapy

    twisted的网络使用 twisted的异步使用 一:简单使用 from twisted.internet import defer from twisted.web.client import g ...

  3. JQ笔记-加强版

    Query初级   一.介绍.基本写法   什么是JQ: 一个优秀的JS库,大型开发必备 JQ的好处: 简化JS的复杂操作 不再需要关心兼容性 提供大量实用方法 如何学习JQ: www.jquery. ...

  4. Spring quartz定时任务service注入问题

    今天想单元测试一下spring中的quartz定时任务,job类的大致结构和下面的SpringQtz1类相似,我的是实现的org.quartz.Job接口,到最后总是发现job类里注入的service ...

  5. 动态内容的缓存技术:CSI vs SSI vs ESI

    CDN 中动态内容是不太好解决的,通常需要很麻烦的技术和方法来实现这些功能,比如我设计过一种动态缓存的方法,基于 session 栏接,然后根据热点来做动态缓存时间的控制.目前开放的实现 Cache ...

  6. Let's Encrypt 免费通配 https 签名证书 安装方法

    安装环境 centOs7 主要通过 acme.sh (bash脚本)来注册签名 git地址:https://github.com/Neilpang/acme.sh 申请证书流程 1.申请证书-> ...

  7. 【leetcode 简单】第五十题 位1的个数

    编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量). 示例 : 输入: 11 输出: 3 解释: 整数 11 的二进制表示为 00000000000 ...

  8. java校验身份证号码

    /** * 18位身份证校验,粗略的校验 * @author lyl * @param idCard * @return */ public static boolean is18ByteIdCard ...

  9. NoSQL-来自维基百科

    NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称. 两者存在许多显著的不同点,其中最重要的是NoSQL不使用SQL作为查询语言.其数据存储可以不需 ...

  10. sql server 2008 r2 产品密钥

    数据中心版:PTTFM-X467G-P7RH2-3Q6CG-4DMYBDDT3B-8W62X-P9JD6-8MX7M-HWK38==================================== ...