并发包之重入锁(synchronized的功能扩展)
重入锁ReentrantLock,就是支持重进入的锁,它表示一个该锁能够支持一个线程对资源的重复加锁,除此之外,该锁还支持取锁时的公平和非公平性选择。Synchronized关键字隐式的支持可重入,比如一个Synchronized修饰的递归方法,在方法执行时,执行线程在获取了锁之后仍能连续多次获得该锁。不会因为获取了锁,下次获取锁的时候就把自己阻塞。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class reentertLock implements Runnable { public static ReentrantLock lock = new ReentrantLock(); public static int i= 0; @Override public void run() { for(int j=0;j<1000;j++) { lock.lock(); try{ i++; }finally { lock.unlock(); } } } public static void main(String[] args) throws Exception { reentertLock r1 =new reentertLock(); Thread t1 =new Thread(r1); Thread t2 =new Thread(r1); t1.start();t2.start(); t1.join();t2.join(); System.out.println(i); } }
|
锁申请等待限时
使用tryLock()方法进行一次限时的等待.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class TimeClock implements Runnable{ public static ReentrantLock lock =new ReentrantLock(); public void run() { try { if(lock.tryLock(5, TimeUnit.SECONDS)) {Thread.sleep(3000);} else {System.out.println("get lock failed");} } catch (InterruptedException e) {e.printStackTrace();} finally { if(lock.isHeldByCurrentThread()) {lock.unlock();} } } public static void main(String[] args) { TimeClock m1 =new TimeClock(); Thread t1 =new Thread(m1); Thread t2 =new Thread(m1); t1.start(); t2.start(); } }
|
公平锁
当使用Synchronized时,产生的锁是非公平的,而重入锁允许对其公平性进行设置 它有一个如下的构造函数
1
| public ReentrantLock(boolean fair)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class fair_lock implements Runnable{ public static ReentrantLock lock =new ReentrantLock(true); public void run() { while(true) { try { lock.lock(); System.out.println(Thread.currentThread().getName()+"获得锁");
}finally { lock.unlock(); } } } public static void main(String[] args) { fair_lock f1 =new fair_lock(); Thread t1 =new Thread(f1,"t1"); Thread t2 =new Thread(f1,"t2"); t1.start(); t2.start(); } }
|
重入锁的重要方法
1 2 3 4 5
| lock():获得锁,如果锁已经被占用,则等待 lockInterruptibly():获得锁,但优先相应中断. tryLock(); 尝试获得锁,如果成功,则返回true,失败返回false,该方法不等待,立即返回 tryLock(Long time ,TimeUnit unit);给定时间内尝试获得锁 unlock()释放锁.
|
Condition条件( 重入锁的好搭档)
Condition 对象和wait()和notify()的作用是大致相同的,但是wait()和notify()是和Synchronized关键字合作使用的,而condition 是和重入锁相关联的
通过Lock接口的Condition new Condition()方法就可以生成一个与当前重入锁绑定的Condition 实例,
通过condition 对象,我们就可以让线程在合适的时间等待,或者在合适的时刻得到通知,继续执行
Condition 接口的基本方法如下:
1 2 3 4 5 6 7 8 9 10 11
| void await(); 使当前线程等待,同时释放当前锁,当其他线程中使用signal()或者signalAll()方法时,线程会重新获得锁并继续执行,或者当线程中断时,也能跳出等待. void awaitUninterruptibly(); 和await()方法基本相同,但是不会在等待过程中相应中断 long awaitNanos(long nanosTimeout) boolean await(long time,TimeUnit unit) boolean awaitUntil(Date deadline) void signal(); 用于唤醒一个等待中的线程. void signalAll(); 唤醒所有等待中的线程.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class Condition_example implements Runnable { public static ReentrantLock lock =new ReentrantLock(); public static Condition condition =lock.newCondition(); public void run() { try { lock.lock(); condition.await(); System.out.println("Thread is going on"); }catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public static void main(String[] args) throws Exception { Condition_example conditionExample =new Condition_example(); Thread t1 =new Thread(conditionExample); t1.start(); Thread.sleep(2000); lock.lock(); condition.signal(); lock.unlock(); } }
|
和wait和notify方法一样,当线程使用condition.await()时,要求线程持有相关的重入锁.