文档章节

java 中的lock锁

勇恒
 勇恒
发布于 2017/07/05 20:22
字数 1603
阅读 6
收藏 0

锁在多线程编程中有很重要的作用,synchronized比较常见也很常用,但是Lock提供了更广泛的锁操作,处理多线程同步的问题也更加优雅和灵活,JavaJava SE 5之后在并发包中提供Lock接口。

一、Lock和synchronized的区别和各自的特点

1、类型不同 
Lock是一个接口,是JDK层面的实现;synchronized是Java的关键字,是JVM层面的实现,是Java的内置特性;这也造成了在锁管理上的不同。 
2、释放锁的方式 
Lock是在编码中进行锁的操作,需要主动调用接口中的方法释放锁,所以使用Lock时需要配合try模块,在finally中释放锁,不然一旦发生异常很可能造成死锁现象;synchronized由于是JVM层面的实现,获取锁和释放锁的操作是不可见的,当发生异常时,锁的释放由JVM实现。 
3、获取锁的过程 
Lock接口中提供的方法,让获取锁的过程更加灵活,编程人员可以方便的在获取锁的过程中进行多种操作,比如尝试获取锁、设置获取锁的超时时间、中断等待获取锁的线程等,应该说让锁的操作变得“丰富多彩”起来;synchronized是无法这么灵活的对锁进行操作的。 
4、效率 
基于读写锁接口的扩展,Lock可以提高多个线程进行读操作的效率,在大并发量的情况下,效率的提高会尤其明显。

二、Lock应用场景举例

1、解决获取锁的等待问题 
如果占有锁的线程A由于各种原因导致阻塞而没有释放锁,此时其他线程B也需要获得该锁。synchronized的机制是让B持续等待,如果A一直没有释放锁,那么B将一直等待,这会很大程度影响执行的效率;而Lock中提供了中断线程等待的方法,也提供了带有超时时间的获取锁的方法,后面会讲到这些方法。 
2、读写锁的分离 
我们知道,多线程仅仅是执行读操作的话是没有冲突问题的,因而在读操作时的锁没必要是独占的。synchronized实现同步就会导致在读操作时只能有一个线程获得锁,其他线程只能等待锁的释放。Lock中的ReentrantReadWriteLock很好的解决了这个问题。 
3、其他锁的操作 
如获知当前线程是否成功获得锁等,synchronized是做不到的。

三、Lock接口中的方法

先看一下Lock的源码,它是一个接口:
public interface Lock {
    void lock();

    void lockInterruptibly() throws InterruptedException;

    boolean tryLock();

    boolean tryLock(long var1, TimeUnit var3) throws InterruptedException;

    void unlock();

    Condition newCondition();
}
  •  

在介绍每个方法之前,先说明两个注意事项: 
1、Lock的实例一般定义为成员变量,如果定义为局部变量,每个线程都会保存一个自己的副本,那么在获取锁的操作时,实际每个线程获取的是不同的锁,无法形成同步互斥访问。 
2、获取锁的操作要放在try模块之外,原因是如果放在try模块内的话,当获取锁的操作发生异常会调用finally中的代码释放锁,而此时可能并没有获取锁,就会抛出异常。 
接下来看一下每个方法的作用: 
1、lock() 
特点:发生异常不自动释放锁;如果没有获取到锁会等待; 
代码示例:

  •  

2、tryLock() 
特点:带有boolean型返回值;无论是否成功获取锁会立即返回不进行等待;

    private Lock lock = new ......; //创建锁

    public void getLock() {

       if(lock.tryLock()) {
           try {
               System.out.print("业务处理"); //任务处理
           } catch (Exception e) {

           } finally {
               lock.unlock(); //释放锁
           }
       } else {
           System.out.print("获取锁失败");
       }

    }
  •  

3、tryLock(long time, TimeUnit unit) 
特点:可以设置获取锁的等待时间,如tryLock(4, TimeUnit.SECONDS)等待4秒;可以在等待过程中相应中断; 
示例代码略,参考tryLock()代码,要注意异常的处理。 
4、lockInterruptibly() 
特点:当一个使用该方法获取锁的线程没有获取到锁处于阻塞等待状态时,可以调用线程的interrupt()方法中断等待。 
示例代码略。

Lock接口有一个实现类ReentrantLock,即可重入锁,除实现Lock接口的方法外,还提供了非常丰富的其他的锁操作方法,如公平锁和非公平锁。

四、读写锁ReadWriteLock

ReadWriteLock是一个接口,接口代码:
  •  
里面只定义了两个方法,一个获取读锁,一个获得写锁,将资源的锁分开为两个,从而使得资源可以在多线程情境下并发读操作。
ReentrantReadWriteLock类实现了ReadWriteLock接口,并提供了更多方法,最主要的还是获取读写锁的方法。
读写锁代码示例:
public class LockTest {
    private ReadWriteLock lock = new ReentrantReadWriteLock(); //创建锁

    public static void main(String[] args) {
        final LockTest lockTest = new LockTest();
        new Thread("A") {
            public void run() {
                lockTest.getLock(Thread.currentThread());
            }
        }.start();
        new Thread("B") {
            public void run() {
                lockTest.getLock(Thread.currentThread());
            }
        }.start();
    }

    public void getLock(Thread thread) {

        lock.readLock().lock(); //获得读锁
        try {
            System.out.println("线程" + thread.getName() + "获得读锁");
            long startTime = System.currentTimeMillis();
            while (System.currentTimeMillis() - startTime <= 1) {
                System.out.println("线程" + thread.getName() + "进行读操作......");
            }

        } catch (Exception e) {

        } finally {
            lock.readLock().unlock();
            System.out.println("线程" + thread.getName() + "释放读锁");
        }

    }
}
  •  

结果: 
这里写图片描述

五、几种锁的概念介绍

1、可重入锁 
具备可重入性的锁,即为可重入锁,比如synchronized和ReentrantLock都是。锁基于线程分配,当某个线程获得了锁去执行某个方法,方法中如果再次需要获取锁资源时,当前线程可以直接获得锁,不必重新申请。 
2、可中断锁 
可以响应中断的锁。synchronized不是可中断锁,但是Lock是可中断锁。 
3、公平锁 
尽量按照请求锁的顺序获得锁。synchronized是非公平锁,ReentrantLock和ReentrantReadWriteLock提供了设置公平锁的方法,不过默认为非公平锁。非公平锁可能导致某些线程永远获取不到锁。 
4、读写锁 
将对资源的锁分为两个,一个读锁和一个写锁,使得多个线程之间的读操作不会发生冲突可以并行,这极大的提高了读的效率。不过读锁和写锁、写锁和写锁之间都是互斥的。

本文转载自:http://blog.csdn.net/qq_25160969/article/details/71335362

共有 人打赏支持
勇恒
粉丝 2
博文 109
码字总数 57634
作品 0
杭州
java Lock interface 与synchronized使用注意--java线程(第三版)

在java中,跟着synchronized关键字的lock都会在thread离开同步块的范围时被释放掉,即使是因为异常而离开范围也是一样。所以在java中使用synchronized关键字时,异常导致不释放锁而导致死锁的...

Beaver_
2015/04/06
0
0
Java轻量级锁原理详解(Lightweight Locking)

大家知道,Java的多线程安全是基于Lock机制实现的,而Lock的性能往往不如人意。 原因是,monitorenter与monitorexit这两个控制多线程同步的bytecode原语,是JVM依赖操作系统互斥(mutex)来实现...

serenity
2015/08/11
0
0
21、Java并发性和多线程-Java中的锁

以下内容转自http://ifeve.com/locks/: 锁像synchronized同步块一样,是一种线程同步机制,但比Java中的synchronized同步块更复杂。因为锁(以及其它更高级的线程同步机制)是由synchronize...

easonjim
2017/06/16
0
0
【Java并发性和多线程】Java中的锁

本文为转载学习 原文链接:http://ifeve.com/locks/ 锁像synchronized同步块一样,是一种线程同步机制,但比Java中的synchronized同步块更复杂。因为锁(以及其它更高级的线程同步机制)是由...

heroShane
2014/02/02
0
0
Java 8新特性探究(十)StampedLock将是解决同步问题的新宠

Java8就像一个宝藏,一个小的API改进,也足与写一篇文章,比如同步,一直是多线程并发编程的一个老话题,相信没有人喜欢同步的代码,这会降低应用的吞吐量等性能指标,最坏的时候会挂起死机,...

OSC闲人
2014/05/13
0
30

没有更多内容

加载失败,请刷新页面

加载更多

下一页

内存模型是怎么解决缓存一致性的?

在再有人问你Java内存模型是什么,就把这篇文章发给他。这篇文章中,我们介绍过关于Java内容模型的来龙去脉。 我们在文章中提到过,由于CPU和主存的处理速度上存在一定差别,为了匹配这种差距...

Java填坑之路
15分钟前
1
0
vue-cli 3.0 初体验

最近复习了下vue,突然发现vue-cli已经更新到3.0版本了,并且变化蛮大,看来要不停的学习,真是一入前端深似海。 安装步骤: 1、全局安装 npm install -g @vue/cli Vue CLI 的包名称由 vue-...

tianyawhl
17分钟前
0
0
Angular进阶之路

【初级】会写页面,能出东西。 给定环境和 rest API,不用第三方库,能在十分钟内完成一个 master/detail 结构的带路由的应用(可以不管美观)。 知识点:Angular CLI、组件、路由、HTTP 服务...

陆小七的主页
20分钟前
0
0
Redis缓存数据库安全加固指导(一)

背景 在众多开源缓存技术中,Redis无疑是目前功能最为强大,应用最多的缓存技术之一,参考2018年国外数据库技术权威网站DB-Engines关于key-value数据库流行度排名,Redis暂列第一位,但是原生...

中间件小哥
20分钟前
0
0
百万级数据mysql分区

1. 什么是表分区? 表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。 2. 表分区与分表的区别 分表...

罗文浩
22分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部