初学JAVA,我们在处理多线程的时候一般使用synchronized关键字来实现同步访问,不过这种方式存在着很多缺陷。大概在jdk1.5之后,在java.util.concurrent.locks包下提供了而一个新的同步访问接口:Lock。

既然已经有了synchronized,为什么还会提供Lock呢?我们就来看看这两者的区别:

1、synchronized是java的关键字,而Lock是一个接口。

2、方法被synchronized修饰了,当一个线程获得对应锁的时候,其他线程只能一直等待,直到锁被释放。而Lock则可以控制是否继续等待。

3、当多个线程同时等待获取锁时,synchronized下线程随机获得锁,而Lock可以控制。

下面先对Lock进行分析,理解能力有限,大神路过勿喷:

首先对 java.util.concurrent.locks包下常用的类和接口一一探讨:

1、Lock:根据源码可看出是一个顶层的接口,接口中的方法如下图


其中lock()、lockInterruptibly()、tryLock()、tryLock(long,TimeUnit)四个为请求锁的方法。四个方法的区别为:

  1. lock()请求锁,如果锁已被获取,则处于等待状态。需要注意的是lock获得锁后,必须手动释放,所以当执行过程中遇到一些异常的时候需要进行捕获,否则容易出现死锁的现象。一般写法如下
Lock lock = ..........
try{
lock.lock();
}finally{
lock.unlock();
}

2. tryLock()和tryLock(long,TimeUnit)请求锁后会立即返回一个boolean类型的值,如果获取不到锁对象,不会一直等待。返回true则获得锁false则未获得,其中后者与前者的区别在于,后者传入参数会等待传入参数的时间,在这个时间内获得锁立即返回,时间到还未获得锁则会返回flase。

tryLock的写法与lock的一般写法有一些区别:

Lock lock = ..........
if(lock.tryLock()){
try{
lock.lock();
}finally{
lock.unlock();
}
}


3. lockInterruptibly()跟lock不同的是,请求锁后等待过程中可以被中断,例如A线程请求锁,发现锁被占用,一直等待,此时可以通过调用interrupt中断锁等待。


锁的概念:

1、可重入锁

一般来说大多数锁都是可重入锁,可重入锁可以这么理解,如下:


public synchronized void method1() {
method2();
 
 
  
 } 

 
 
 public 
   
 synchronized 
   
 void 
   
 method2() { 

 
 
 }


当一个线程获得锁,执行method1,method1中存在synchronized修饰的method2,如果锁不具有可重入性则需要重新获得锁才能执行method2方法,而synchronized和lock是可重入锁,不用再次获得锁就可以执行method2方法。

2、 可中断锁

等待过程中可以被中断的锁,在获取锁时,锁已被占用,则需要等待,可中断锁则可以在此时中断等待。lock属于可中断锁,而synchronized不属于可中断锁。

3、公平锁

公平锁即尽量以请求锁的顺序来获取锁。比如同是有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该所,这种就是公平锁。

   非公平锁即无法保证锁的获取是按照请求锁的顺序进行的。这样就可能导致某个或者一些线程永远获取不到锁。

4. 读写锁

  读写锁将对一个资源(比如文件)的访问分成了2个锁,一个读锁和一个写锁。

  正因为有了读写锁,才使得多个线程之间的读操作不会发生冲突。

  ReadWriteLock就是读写锁,它是一个接口,ReentrantReadWriteLock实现了这个接口。

  可以通过readLock()获取读锁,通过writeLock()获取写锁。

以上只是对lock使用方法和概念的理解,比较浅显。更多深的东西需要再细细理解,比如锁的获取过程,等待线程分配锁是如何实现的等等,这些在以后都会分享出来。