java Lock

一、Lock锁:

  Lock是一个接口,Lock需要手动的释放锁,Lock锁可以知道是否成功的获取锁。

 

二、Lock接口中的方法

  

  获取锁:Lock() tryLock()tyrLock(long time,timeUnit unit)lockInterruptibly()

 

  释放锁:unlock()

  

 四种获取锁方法的区别:

  1.Lock()这种方法是最常用的方法,

  由于在前面讲到Lock锁必须手动释放锁,并且在发生异常时不会自动释放锁。因此一般来说,使用Lock必须在try{}catch(){}  中。而释放锁的过程放在finally中,以保证锁即使在异常的情况下也能被正常的释放,防止死锁的发生。

  Lock lock = ...;

  lock.lock();

  try{

      //处理任务

  }catch(Exception ex){

     

  }finally{

      lock.unlock();   //释放锁

  }

 

  2.tryLock()方法是有返回值的方法,此方法可用来判断是否获取了锁,如果获取了锁,返回值为true,如果获取失败(即锁已被其它线程占用),则返回值为false。也就是说这个方法不会一直原地等待,无论是否拿到锁都会立即返回。

 

Lock lock = ...;
if(lock.tryLock()) {
     try{
         //处理任务
     }catch(Exception ex){
         
     }finally{
         lock.unlock();   //释放锁
     } 
}else {
    //如果不能获取锁,则直接做其他事情
}

 

  3.tryLock(long time,timeUnit time)方法和tryLock() 方法类似,不同的是此方法在拿不到锁会等待一段时间,如果在期限的时间内还拿不到锁,就不再等待,而是返回false。如果一开始或期限时间内拿到锁,就返回true

 

  4.lockInterruptibly()方法比较特殊,当用西方法获取锁的时候,如果线程处在没有获取到锁,而正在等待获取锁,那么这个线程是可以被中断,即中断线程的等待状态。也就是说,当两个线程同时通过lock.lockInterruptibly()向获取锁时,加入线程A获取了锁,线程B只能等待,那么对线程B调用B.lockInterruptibly() 是中断线程B的等待过程。

 

 

注意:当一个线程获取了锁之后是不会被interrupt()方法打断的,interrupt()可以打断正在阻塞的线程,不可以打断正在执行的进程。

 

因此当通过lockInterruptibly()方法获取锁时,如果获取不到,只有进行等待的情况下,是可以响应中断的。而如果使用synchronized修饰的话,当一个线程处于正在等待某个锁的状态没事无法中断的,只能一直等待下去。

三、ReentrantLock

  

  意思是可重入锁,是Lock接口的实现类。

  来看一个实例

 1.lock()方法

public class TestLock {
    public static void main(String[] args) {
        Thread1 thread=new Thread1();
        Thread thread1=new Thread(thread);
        Thread thread2=new Thread(thread);
        thread1.start();
        thread2.start();
    }
}
class Thread1  implements  Runnable{
    private   Lock lock=new ReentrantLock();
    public void run(){
        lock.lock();
        try{
            for (int i = 0; i < 20; i++) {
                System.out.println(Thread.currentThread().getName()+"i "+i);
            }
        }catch (Exception  e){
            e.printStackTrace();
        }finally {
          lock.unlock();
        }
    }
}

 运行结果:

  2.tryLock() 方法的使用

public class TestLock {
    public static void main(String[] args) {
        Thread1 thread = new Thread1();
        Thread thread1 = new Thread(thread);
        Thread thread2 = new Thread(thread);
        thread1.start();
        thread2.start();
    }
}

class Thread1 implements Runnable {
    //公用一把锁
    private Lock lock = new ReentrantLock();

    public void run() {

        if (lock.tryLock()) {
            try {
                System.out.println(Thread.currentThread().getName()+"获取了锁");
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName() + "i " + i);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName()+"释放了锁");
                lock.unlock();
            }
        }else{
            System.out.println(Thread.currentThread().getName()+"获取锁失败");
        }

    }
}

运行结果:

 

 

四、ReadWriteLock

  ReadWriteLock是一个接口,在里面只定义了两个方法:

public interface ReadWriteLock {

    /**

     * Returns the lock used for reading.

     *

     * @return the lock used for reading.

     */

    Lock readLock();

 

    /**

     * Returns the lock used for writing.

     *

     * @return the lock used for writing.

     */

    Lock writeLock();

}

readLock()方法是用来获取读锁,writelock()是用来获取写锁,也就是将文件的读写操作分开,分成2个锁操作来分配给线程,从而使得多个线程可以同时进行读操锁。

五、ReentrantReadWriteLock 

  ReentrantReadWriteLock实现了ReadWriteLockReentrantReadWriteLock提供了很多方法,不过最重要的两个方法:readLock()WriteLock()来获取读锁和写锁。

 

public class MyReentrantReadWriteLock {
    private ReentrantReadWriteLock rrwl=new ReentrantReadWriteLock();

    public static void main(String[] args) {
        MyReentrantReadWriteLock m=new MyReentrantReadWriteLock();
        new Thread(){
            public void run(){
                m.get(Thread.currentThread());
            }
        }.start();
        new Thread(){
            public void run(){
                m.get(Thread.currentThread());
            }
        }.start();
    }
    public void get(Thread thread){
        rrwl.readLock().lock();
        try{
            System.out.println(thread.getName()+"得到锁");
            long start=System.currentTimeMillis();
            while(System.currentTimeMillis()-start<=1){
                System.out.println(thread.getName()+"正在读取文件");
            }
        }finally {
            System.out.println(thread.getName()+"释放锁");
            rrwl.readLock().unlock();
        }
    }
}

 

 

运行结果:

 

 

 六、与synchronized的区别

  1)在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降很多,但是ReetrantLock的性能能维持常态。

    2)Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;

  3)Lock和synchronized有一点非常大的不同,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。

 

posted @ 2017-12-06 17:10  薛小生  阅读(279)  评论(0编辑  收藏  举报