Java中Lock框架学习笔记

      锁在多线程编程中有很重要的做用,synchronized比较常见也很经常使用,可是Lock提供了更普遍的锁操做,处理多线程同步的问题也更加优雅和灵活,Java从Java SE 5以后在并发包中提供Lock接口。编程

1、Lock和synchronized的区别和各自的特色多线程

一、类型不一样
Lock是一个接口,是JDK层面的实现;synchronized是Java的关键字,是JVM层面的实现,是Java的内置特性;这也形成了在锁管理上的不一样。
二、释放锁的方式
Lock是在编码中进行锁的操做,须要主动调用接口中的方法释放锁,因此使用Lock时须要配合try模块,在finally中释放锁,否则一旦发生异常极可能形成死锁现象;synchronized因为是JVM层面的实现,获取锁和释放锁的操做是不可见的,当发生异常时,锁的释放由JVM实现。
三、获取锁的过程
Lock接口中提供的方法,让获取锁的过程更加灵活,编程人员能够方便的在获取锁的过程当中进行多种操做,好比尝试获取锁、设置获取锁的超时时间、中断等待获取锁的线程等,应该说让锁的操做变得“丰富多彩”起来;synchronized是没法这么灵活的对锁进行操做的。
四、效率
基于读写锁接口的扩展,Lock能够提升多个线程进行读操做的效率,在大并发量的状况下,效率的提升会尤为明显。并发

2、Lock应用场景举例编码

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

3、Lock接口中的方法线程

先看一下Lock的源码,它是一个接口:接口

 

public interface Lock {资源

    void lock();get

 

    void lockInterruptibly() throws InterruptedException;同步

 

    boolean tryLock();

 

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

 

    void unlock();

 

    Condition newCondition();

}

 

在介绍每一个方法以前,先说明两个注意事项:
一、Lock的实例通常定义为成员变量,若是定义为局部变量,每一个线程都会保存一个本身的副本,那么在获取锁的操做时,实际每一个线程获取的是不一样的锁,没法造成同步互斥访问。
二、获取锁的操做要放在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接口的方法外,还提供了很是丰富的其余的锁操做方法,如公平锁和非公平锁。

·

4、读写锁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() + "释放读锁");

        }

 

    }

}

结果:

5、几种锁的概念介绍

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

相关文章
相关标签/搜索