ReentrantLock API
java可重入锁,简单几个小案例,测试特性。
1.尝试锁 tryLock
package com.cn.cfang.ReentrantLock; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Test02 { private Lock lock = new ReentrantLock(); private void m1(){ try{ lock.lock(); for(int i = 0; i < 10; i++){ TimeUnit.SECONDS.sleep(1); System.out.println("m1() method " + i); } }catch(InterruptedException e){ e.printStackTrace(); }finally{ lock.unlock(); } } private void m2(){ boolean isLocked = false; try { //尝试锁,如果已被其他线程锁住,无法获取锁标记,则返回false //相反,如果获取锁标记,则返回true //isLocked = lock.tryLock(); //阻塞尝试锁:会阻塞参数代表的时长,再去尝试获取锁标记 //如果超时未获取,不继续等待,直接返回false //阻塞尝试锁类似于自旋锁。 isLocked = lock.tryLock(11, TimeUnit.SECONDS); if(isLocked){ System.out.println("method m2 synchronized"); }else{ System.out.println("method m2 unsynchronized"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ if(isLocked){ lock.unlock(); } } } public static void main(String[] args) { Test02 t = new Test02(); new Thread(new Runnable() { @Override public void run() { t.m1(); } }).start(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(new Runnable() { @Override public void run() { t.m2(); } }).start(); } }
2. 可中断
package com.cn.cfang.ReentrantLock; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * ReentrantLock的可打断性 * * 打断 : 调用thread.interrupt()方法,可打断线程阻塞状态,抛出异常。 * 可尝试打断,阻塞等待锁。 * * 阻塞状态 :包括普通阻塞状态,等待队列,锁池队列 * 普通阻塞 : sleep,可以被打断。 * 等待队列 : wait方法调用,也是一种阻塞状态,不能被打断,只能等待notify * 锁池队列 : 无法获取锁标记。不是所有的锁池队列都能被打断 * ReentrantLock的lock获取锁标记的时候,如果未获取,需要阻塞的去等待锁标记,无法被打断 * ReentrantLock的lockInterruptibly获取锁标记的时候,如果未获取,需要阻塞等待,可以被打断 * * @author cfang * 2018年5月4日 下午2:23:41 */ public class Test03 { private Lock lock = new ReentrantLock(); private void m1(){ try { lock.lock(); for(int i = 0; i < 5; i++){ TimeUnit.SECONDS.sleep(1); System.out.println("m1() method " + i); } } catch (InterruptedException e) { e.printStackTrace(); }finally{ lock.unlock(); } } private void m2(){ try { lock.lockInterruptibly(); //可尝试打断,阻塞等待锁,可以被其他的线程打断阻塞状态 System.out.println("m2() method"); } catch (InterruptedException e) { // e.printStackTrace(); }finally{ //可能异常打断,所以释放锁标记必须进行异常处理 try { lock.unlock(); } catch (Exception e2) { e2.printStackTrace(); } } } public static void main(String[] args) { Test03 t = new Test03(); new Thread(new Runnable() { @Override public void run() { t.m1(); } }).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } Thread t2 = new Thread(new Runnable() { @Override public void run() { t.m2(); } }); t2.start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } t2.interrupt(); //打断线程休眠阻塞等待。非正常结束阻塞状态的线程,都会抛出异常。 } }
3. 公平锁 : ReentrantLock可定义公平锁,多个线程竞争锁标记的时候,公平锁会记录等待时长,当前线程执行结束后,会优先选取等待时长最长的线程,去获取锁标记执行。
synchronized不具有此特性。
1 package com.cn.cfang.ReentrantLock; 2 3 import java.util.concurrent.TimeUnit; 4 import java.util.concurrent.locks.Lock; 5 import java.util.concurrent.locks.ReentrantLock; 6 7 public class Test04 { 8 9 public static void main(String[] args) { 10 TestReentrantlock t = new TestReentrantlock(); 11 new Thread(t).start(); 12 new Thread(t).start(); 13 } 14 15 } 16 17 class TestReentrantlock implements Runnable{ 18 19 private Lock lock = new ReentrantLock(true); //加参数true,代表公平锁 20 @Override 21 public void run() { 22 for (int i = 0; i < 5; i++) { 23 lock.lock(); 24 try { 25 System.out.println(Thread.currentThread().getName() + " get lock"); 26 }finally{ 27 lock.unlock(); 28 } 29 } 30 } 31 }