JAVA并发-显式锁(一)

JAVA语言除了提供内置锁synchronized,还在JDK6之后提供了高级的显式锁Lock作为功能上的补充。在大多数情况下,内置锁都能很好的工作,我们也尽量使用内置锁。但必须承认的是,内置锁存在一些局限性。比如:无法中断一个正在等待获取锁的线程;无法在请求一个锁时无限等待下去;无法实现非阻塞的加锁规则。当程序中需要这些高级的功能时,考虑使用显式锁。我们来介绍2种显示锁,Lock和ReadWriteLock。

下面是Lock的定义:

public interface Lock {
    //获得锁,在得到锁之前无限等待
    void lock();
    //获得锁,在得到锁之前允许线程被中断
    void lockInterruptibly() throws InterruptedException;
    //返回true,代表获得锁成功;返回false,代表获得锁失败
    boolean tryLock();
    //返回true,代表在指定时间内获得锁成功;返回false,代表在指定时间内获得锁失败
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    //释放锁
    void unlock();
    //返回一个用于线程间通信的实例,关于Condition接口的介绍,参见博客<条件队列(二)>
    Condition newCondition();
}


ReentrantLock是一个实现了Lock接口的类,是一个可重入锁(博客《显式锁(二)》有介绍),下面是一些例子。

 

//lock()的使用
class Test{
	private Lock lock=new ReentrantLock(); 
	public void fun(){
		lock.lock();
		try{
			
		}catch(Exception e){
			
		}finally{
			lock.unlock();
		}
	}
}

 

//tryLock()的使用
class Test{
	private Lock lock=new ReentrantLock();
	public void fun(){
		if(lock.tryLock()){
			try{
				
			}catch(Exception e){
				
			}finally{
				lock.unlock();
			}
		}else{
			
		}
	}
}

 

//lockInterruptibly()的使用
class Test{
	private Lock lock=new ReentrantLock();
	
	public void fun() {
		try{
			lock.lockInterruptibly();
			try{
				
			}catch(Exception e){
				
			}finally{
				lock.unlock();
			}
		}catch(InterruptedException e){
			//抛出异常或者恢复中断
		}
	}
}



下面是ReadWriteLock的定义:

 

public interface ReadWriteLock {
    Lock readLock();
    Lock writeLock();
}



ReadWriteLock的好处是在保证写操作安全性的前提下,能够使读操作并发进行(即:允许并发的读读,但必须互斥的读写,写读,写写)。ReentrantReadWriteLock是实现ReadWriteLock接口的类,使用方法如下:

 

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Demo{
	public static void main(String [] args) throws InterruptedException   {
        final Test test = new Test();
        new Thread(){
            public void run() {
                test.get(Thread.currentThread());
            };
        }.start();
         
        new Thread(){
            public void run() {
                test.get(Thread.currentThread());
            };
        }.start();
	}
}

class Test {
    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    private Lock rLock=rwl.readLock();
    private Lock wLock=rwl.writeLock();
    public void get(Thread thread) {
        rLock.lock();
        try {
            long start = System.currentTimeMillis();
            while(System.currentTimeMillis() - start <= 100) {
                System.out.println(thread.getName()+"正在进行读操作");
            }
            System.out.println(thread.getName()+"读操作完毕");
        } finally {
            rLock.unlock();
        }
    }
}



synchronized和Lock的区别:
1. synchronized自动释放锁,Lock必须在finally块中手动释放锁
2. Lock能够提供一些高级功能,比如:非阻塞的加锁,等待时响应中断,无限等待等
3. synchronized是内置锁,由JVM支持;Lock是JAVA语言级别的锁机制

 

4. synchronized是非公平锁;Lock默认是非公平锁,但可以设置为公平锁。

注意:在上面的所有例子中,你会发现,在获得锁时,语句都是在try块之前,这是必须的。因为如果放到try块里面,在获取锁发生unchecked异常的时,将触发一次释放锁的操作。但实际上,此时并没有占有锁,为此会导致另一个异常IllegalMonitorStateException。

 

 


笔者开设了一个知乎live,详细的介绍的JAVA从入门到精通该如何学,学什么?

提供给想深入学习和提高JAVA能力的同学,欢迎收听https://www.zhihu.com/lives/932192204248682496

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值