博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java中Lock框架学习笔记
阅读量:5878 次
发布时间:2019-06-19

本文共 3631 字,大约阅读时间需要 12 分钟。

hot3.png

      锁在多线程编程中有很重要的作用,synchronized比较常见也很常用,但是Lock提供了更广泛的锁操作,处理多线程同步的问题也更加优雅和灵活,Java从Java 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()
特点:发生异常不自动释放锁;如果没有获取到锁会等待;
代码示例:

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

 

    public void getLock() {

        lock.lock(); //获得锁

        try {

            System.out.print("业务处理"); //任务处理

        } catch (Exception e) {

 

        } finally {

            lock.unlock(); //释放锁

        }

    }

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是一个接口,接口代码:

·

public interface ReadWriteLock {

    Lock readLock(); //读锁

 

    Lock writeLock(); //写锁

}

里面只定义了两个方法,一个获取读锁,一个获得写锁,将资源的锁分开为两个,从而使得资源可以在多线程情境下并发读操作。

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、读写锁
将对资源的锁分为两个,一个读锁和一个写锁,使得多个线程之间的读操作不会发生冲突可以并行,这极大的提高了读的效率。不过读锁和写锁、写锁和写锁之间都是互斥的。

 

转载于:https://my.oschina.net/iioschina/blog/1789977

你可能感兴趣的文章
TextKit简单示例
查看>>
网格最短路径算法(Dijkstra & Fast Marching)(转)
查看>>
最短路径算法-Dijkstra算法的应用之单词转换(词梯问题)
查看>>
软链接和硬链接详解
查看>>
HTML5 video 视频标签 常用属性
查看>>
深入理解javascript对象系列第一篇——初识对象
查看>>
Redis_master-slave模式
查看>>
qemu安装
查看>>
多媒体开发之rtmp---rtmp client 端的实现
查看>>
3.使用Maven构建Web项目
查看>>
cisco 多生成树MST笔记
查看>>
C 到 C++ 的升级(一)
查看>>
彻底卸载删除微软Win10易升方法
查看>>
Ajaxload动态加载动画生成工具的实现(ajaxload的本地移植)
查看>>
SWT/JFACE之环境配置(一)
查看>>
手把手构建LAMP
查看>>
关于outlook 保存的.msg文件打开一次之后不能再次打开的问题
查看>>
CentOS 6.6安装python3.4.3后yum不能使用的解决办法
查看>>
应用程序日志中总是说MS DTC无法正确处理DC 升级/降级事件,是什么意思
查看>>
毕业了,爱情怎么办?
查看>>