Lock常用方法和读写锁讲解

发表时间:2017-09-07 16:41:15 浏览量( 20 ) 留言数( 0 )

学习目标:

1、了解lock的常用方法

2、了解读写锁的使用


学习过程:

一、lock的常用方法

获得锁的方法

1、构造方法Reentrantlock(boolean fair)

   Reentrantlock(boolean fair): 创建一个拥有指定公平策略的Reentrant Lock 的实例。当这个锁需要使用公平的排序策略时,给fair俨赋值为true 。在争用的环境下,这个锁倾向于将访问权限分配,给等待最久的线程。

2、lock()

首先lock()方法是平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他线程获取,则进行等待。在前面的例子中都是使用这个lock()方法。

3、tryLock()

   tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。

   tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。

  所以,一般情况下通过tryLock来获取锁时是这样使用的:

Lock lock = ...;

if(lock.tryLock()) {

     try{

         //处理任务

     }catch(Exception ex){

         

     }finally{

         lock.unlock();   //释放锁

     } 

}else {

    //如果不能获取锁,则直接做其他事情


4、lockInterruptibly()

    lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。

public void method() throws InterruptedException {

    lock.lockInterruptibly();

    try {  

     //.....

    }

    finally {

        lock.unlock();

    }  

}


另外在ReentrantLock类中定义了很多方法,比如:

  isFair()        //判断锁是否是公平锁

  isLocked()    //判断锁是否被任何线程获取了

  isHeldByCurrentThread()   //判断锁是否被当前线程获取了

  hasQueuedThreads()   //判断是否有线程在等待该锁




二、读写锁

   ReadWriteLock接口定义了获得读锁和写锁。也就是说将读写操作分开,分成2个锁来分配给线程,从而使得多个线程可以同时进行读操作。ReentrantReadWriteLock实现了ReadWriteLock接口。

  ReentrantReadWriteLock里面提供了很多丰富的方法,不过最主要的有两个方法:readLock()和writeLock()用来获取读锁和写锁。

    锁框架针对这些场景提供了读一写锁机制,在读取时有更好的并发性,而写入时保证安全的互斥访问。这一机制基于接口ReadWritelock 。对应一些经常需要读取的操作,Lock会有更高的性能。

(1)资源类

public class MyServiceReadWrite {

	private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

	public void read1() {
		lock.readLock().lock();

		try {
			System.out.println("我是read1,我获得锁了。");
			Thread.sleep(2000);// 模拟运行两秒
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			System.out.println("我是read1,释放了。");
			lock.readLock().unlock();
		}

	}

	public void read2() {
		lock.readLock().lock();

		try {
			System.out.println("我是read2,我获得锁了。");
			Thread.sleep(2000);// 模拟运行两秒
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			System.out.println("我是read2,释放了。");
			lock.readLock().unlock();
		}

	}

	public void write() {
		lock.writeLock().lock();

		try {
			System.out.println("我是write,我获得锁了。");
			Thread.sleep(2000);// 模拟运行两秒
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			System.out.println("我是write,释放了。");
			lock.writeLock().unlock();
		}

	}
}

(2)读线程类

有两个线程都是读取的。

public class MyThreadRead1 extends Thread {

	private MyServiceReadWrite myService;

	public MyThreadRead1(MyServiceReadWrite myService) {
		this.myService = myService;
	}

	public void run() {
        myService.read1();
	}

}

第二个:

public class MyThreadRead2 extends Thread {

	private MyServiceReadWrite myService;

	public MyThreadRead2(MyServiceReadWrite myService) {
		this.myService = myService;
	}

	public void run() {
        myService.read2();
	}

}

(3)写线程类

public class MyThreadWrite extends Thread {

	private MyServiceReadWrite myService;

	public MyThreadWrite(MyServiceReadWrite myService) {
		this.myService = myService;
	}

	public void run() {
        myService.write();
	}

}

(4)运行类

public class RunWriteRead {
	
	public static void main(String[] args) {
		
		MyServiceReadWrite myService=new MyServiceReadWrite();
		
		MyThreadRead1 myThreadRead1=new MyThreadRead1(myService);
		MyThreadRead2 myThreadRead2=new MyThreadRead2(myService);
		MyThreadWrite myThreadWrite=new MyThreadWrite(myService);
		
		myThreadRead1.start();
		myThreadRead2.start();
		myThreadWrite.start();
		
	}

}

两个读锁可以同时进入,但是如果是写锁则必须等待锁的释放。

三、总结

总结来说,Lock和synchronized有以下几点不同:

  1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;

  2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

  3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

  4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

  5)Lock可以提高多个线程进行读操作的效率。