ReentrantLock
1.ReentrantLock概述
在java多线程中,可以使用synchronized关键字来实现线程之间同步互斥,但在JDK1.5中增加了ReentrantLock也能达到同样的效果,并且在扩展功能上也更加强大,而且使用上更加灵活。
使用ReentrantLock实现生产者消费者:
package chapter4.reentrant; import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class MyStack { private List<String> list = new ArrayList<>(); ReentrantLock lock = new ReentrantLock(); Condition conditionp = lock.newCondition(); Condition conditionc = lock.newCondition(); public void push() { try { lock.lock(); while(list.size() == 1) { System.out.println("push 操作中的:"+Thread.currentThread().getName()+" 线程呈等待状态"); conditionp.await(); } list.add("anything="+Math.random()); conditionc.signalAll(); System.out.println("push="+list.size()); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void pop() { try { lock.lock(); while(list.size() == 0) { System.out.println("pop 操作中的:"+Thread.currentThread().getName()+" 线程呈等待状态"); conditionc.await(); } String str = list.get(0); System.out.println("pop "+str); list.remove(0); conditionp.signalAll(); System.out.println("pop="+list.size()); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } } package chapter4.reentrant; public class P { private MyStack myStack; public P(MyStack myStack) { this.myStack = myStack; } public void pushService() { myStack.push();; } } package chapter4.reentrant; public class C { private MyStack myStack; public C(MyStack myStack) { this.myStack = myStack; } public void popService() { myStack.pop();; } } package chapter4.reentrant; public class ThreadP extends Thread{ private P p; public ThreadP(P p) { this.p = p; } @Override public void run() { super.run(); p.pushService(); } } package chapter4.reentrant; public class ThreadC extends Thread{ private C c; public ThreadC(C c) { this.c = c; } @Override public void run() { super.run(); c.popService(); } } package chapter4.reentrant; public class Run { public static void main(String[] args) { try { int cnt=3; MyStack myStack = new MyStack(); P[] pArr = new P[cnt]; C[] cArr = new C[cnt]; for(int i=0;i<cnt;i++) { pArr[i] =new P(myStack); cArr[i] = new C(myStack);; } ThreadP[] threadPs = new ThreadP[cnt]; ThreadC[] threadCs = new ThreadC[cnt]; for(int i=0;i<cnt;i++) { threadPs[i] = new ThreadP(pArr[i]); threadCs[i] = new ThreadC(cArr[i]); } for(int i=0;i<cnt;i++) { threadCs[i].start(); } Thread.sleep(1000); for(int i=0;i<cnt;i++) { threadPs[i].start(); } } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果:
pop 操作中的:Thread-1 线程呈等待状态
pop 操作中的:Thread-3 线程呈等待状态
pop 操作中的:Thread-5 线程呈等待状态
push=1
push 操作中的:Thread-2 线程呈等待状态
push 操作中的:Thread-4 线程呈等待状态
pop anything=0.04358985658650283
pop=0
pop 操作中的:Thread-3 线程呈等待状态
pop 操作中的:Thread-5 线程呈等待状态
push=1
push 操作中的:Thread-4 线程呈等待状态
pop anything=0.8139775455313625
pop=0
pop 操作中的:Thread-5 线程呈等待状态
push=1
pop anything=0.8443402579212704
pop=0
2.ReentrantLock方法介绍
- int getQueueLength():返回正等待获取此锁定的线程估计数。
package chapter4.reentrantmethod; import java.util.concurrent.locks.ReentrantLock; public class Service { public ReentrantLock lock = new ReentrantLock(); public void method() { try { lock.lock(); System.out.println("ThreadName:"+Thread.currentThread().getName()+"进入方法!"); Thread.sleep(Integer.MAX_VALUE); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } } package chapter4.reentrantmethod; public class Run { public static void main(String[] args) { try { final Service service = new Service(); Runnable runnable = new Runnable() { public void run() { service.method(); } }; Thread[] threads = new Thread[10]; for(int i=0;i<10;i++) { threads[i] = new Thread(runnable); } for(int i=0;i<10;i++) { threads[i].start(); } Thread.sleep(2000); System.out.println(service.lock.getQueueLength()+"个线程在等待获取锁"); } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
ThreadName:Thread-0进入方法!
9个线程在等待获取锁
- int getHoldCount():查询当前线程保持此锁定的个数,也就是调用lock()方法的次数。
package chapter4.reentrantmethod; import java.util.concurrent.locks.ReentrantLock; public class Service { public ReentrantLock lock = new ReentrantLock(); public void method1() { try { lock.lock(); System.out.println("method1 getHoldCount:"+lock.getHoldCount()); method2(); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void method2() { try { lock.lock(); System.out.println("method2 getHoldCount:"+lock.getHoldCount()); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } } package chapter4.reentrantmethod; public class Run { public static void main(String[] args) { Service service = new Service(); service.method1(); } }
运行结果:
method1 getHoldCount:1
method2 getHoldCount:2
- boolean hasWaiters(Condition condition):查询是否有线程正在等待与此锁定有关的Condition条件。
- int getWaitQueueLength(Condition condition):返回等待与此锁定条件相关的给定条件Condition的线程估计数。
package chapter4.reentrantmethod; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class Service { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void waitMethod() { try { lock.lock(); condition.await(); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void notifyMethod() { try { lock.lock();
System.out.println("是否有线程正在等待condition:"+lock.hasWaiters(condition)); System.out.println(lock.getWaitQueueLength(condition)+"个线程正在等待condition"); condition.signalAll(); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } } package chapter4.reentrantmethod; public class Run { public static void main(String[] args) { try { final Service service = new Service(); Runnable runnable = new Runnable() { public void run() { service.waitMethod(); } }; Thread[] threads = new Thread[10]; for(int i=0;i<10;i++) { threads[i] = new Thread(runnable); } for(int i=0;i<10;i++) { threads[i].start(); } Thread.sleep(2000); service.notifyMethod(); } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
是否有线程正在等待condition:true
10个线程正在等待condition
- boolean hasQueuedThread(Thread thread):查询指定的线程是否正在等待获取此锁定。
- boolean hasQueuedThreads():查询是否有线程正在等待获取此锁定。
package chapter4.reentrantmethod; import java.util.concurrent.locks.ReentrantLock; public class Service2 { public ReentrantLock lock = new ReentrantLock(); public void waitMethod() { try { lock.lock(); Thread.sleep(Integer.MAX_VALUE); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } } package chapter4.reentrantmethod; public class Run2 { public static void main(String[] args) { try { final Service2 service = new Service2(); Runnable runnable = new Runnable() { public void run() { service.waitMethod(); } }; Thread threada = new Thread(runnable); threada.start(); Thread.sleep(500); Thread threadb = new Thread(runnable); threadb.start(); Thread.sleep(500); System.out.println(service.lock.hasQueuedThread(threada)); System.out.println(service.lock.hasQueuedThread(threadb)); System.out.println(service.lock.hasQueuedThreads()); } catch (Exception e) { e.printStackTrace(); } } }
执行结果:
false
true
true
- boolean isFair():判断是不是公平锁,ReentrantLock类默认使用的是非公平锁。
- boolean isHeldByCurrentThread():查询当前线程是否保持此锁定。
- boolean isLocked():此锁定是否由任意线程保持。
- void lockInterruptibly():如果当前线程未被中断,则获取锁定,如果已经被中断则出现异常。
- boolean tryLock():仅在调用时锁定未被另一个线程保持的情况下,才获取该锁定。
- boolean tryLock(long timeout, TimeUnit unit):如果锁定在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。
- void awaitUninterruptibly():线程被中断,不会抛出异常。
- boolean awaitUntil(Date deadline):wait到某一个时间点,可以被提前唤醒。
3.ReentrantReadWriteLock
- readLock().lock();//获取读锁
- readLock().unlock();//释放读锁
- writeLock().lock();//获取写锁
- writeLock().unlock();//释放写锁
读读共享,写写互斥,读写互斥,写读互斥。