Lock的使用
4.1 使用ReentrantLock类
在JKD1.5中,新增加了ReentrantLock类也能达到和synchronized关键字同样的效果,并且在扩展功能上更加强大,如嗅探锁定,多路分支通知等功能,在使用上也比synchronized更加灵活。
package ReentrantLock; /* * lock.lock() 代码的线程持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢 */ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class t1 { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); MyThreadA a1 = new MyThreadA(service); a1.setName("A"); a1.start(); MyThreadAA a2 = new MyThreadAA(service); a2.setName("AA"); a2.start(); Thread.sleep(100); MyThreadB a3 = new MyThreadB(service); a3.setName("B"); a3.start(); MyThreadBB a4 = new MyThreadBB(service); a4.setName("BB"); a4.start(); } } class MyService { private Lock lock = new ReentrantLock(); public void MethodA() { try { lock.lock(); System.out.println("methodA begin ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis()); Thread.sleep(5000); System.out.println("methodA end ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis()); }catch (InterruptedException e) { // TODO: handle exception e.printStackTrace(); }finally{ //不管是否发生异常,该代码块都执行 lock.unlock(); } } public void MethodB() { try { lock.lock(); System.out.println("methodB begin ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis()); Thread.sleep(5000); System.out.println("methodB end ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis()); }catch (InterruptedException e) { // TODO: handle exception e.printStackTrace(); }finally{ //不管是否发生异常,该代码块都执行 lock.unlock(); } } } class MyThreadA extends Thread { private MyService service; public MyThreadA(MyService service) { this.service = service; } @Override public void run() { super.run(); service.MethodA(); } } class MyThreadAA extends Thread { private MyService service; public MyThreadAA(MyService service) { this.service = service; } @Override public void run() { super.run(); service.MethodA(); } } class MyThreadB extends Thread { private MyService service; public MyThreadB(MyService service) { this.service = service; } @Override public void run() { super.run(); service.MethodB(); } } class MyThreadBB extends Thread { private MyService service; public MyThreadBB(MyService service) { this.service = service; } @Override public void run() { super.run(); service.MethodB(); } }
methodA begin ThreadName=A time=1603976169500 methodA end ThreadName=A time=1603976174512 methodA begin ThreadName=AA time=1603976174512 methodA end ThreadName=AA time=1603976179521 methodB begin ThreadName=B time=1603976179521 methodB end ThreadName=B time=1603976184522 methodB begin ThreadName=BB time=1603976184522 methodB end ThreadName=BB time=1603976189534
此实验说明,调用lock.lock()代码的线程就持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢。
4.1.3 使用Condition实现等待/通知
类ReentrantLock也可以实现等待/通知模式,需要借助Condition对象。在一个Lock对象里可以创建多个Condition(即对象监视器)实例,线程对象可以注册在指定的Condition中,从而可以有选择地进行线程通知,在调度线程上更加灵活。对比notify/notifyAll方法,被通知的线程却是由JVM随机选择的。
/* * lock.lock() 代码的线程持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢 */ package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class t1 { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); MyThread a1 = new MyThread(service); a1.start(); Thread.sleep(3000); service.signal(); } } class MyService { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void await() { try { lock.lock(); System.out.println("waitMethod时间为 " + System.currentTimeMillis()); condition.await(); }catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); System.out.println("锁释放了!"); } } public void signal() { try { lock.lock(); System.out.println("signal时间为" + System.currentTimeMillis()); condition.signal(); }catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); System.out.println("我已经唤醒了await()方法,我也该结束了"); } } } class MyThread extends Thread { private MyService service; public MyThread(MyService service) { this.service = service; } @Override public void run() { super.run(); service.await(); } }
waitMethod时间为 1603978989457 signal时间为1603978992471 我已经唤醒了await()方法,我也该结束了 锁释放了!
Object类中的wait()相当于Condition类中的await()方法。
Object类中的notify()相当于Condition类中的signal()方法。
/* * lock.lock() 代码的线程持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢 */ package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class t1 { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); MyThreadA a = new MyThreadA(service); a.setName("A"); a.start(); MyThreadB b = new MyThreadB(service); b.setName("B"); b.start(); Thread.sleep(3000); //service.signalAll_A(); service.signalAll_B(); } } class MyService { private Lock lock = new ReentrantLock(); public Condition conditionA = lock.newCondition(); public Condition conditionB = lock.newCondition(); public void awaitA() { try { lock.lock(); System.out.println("begin awaitA时间为 " + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName()); conditionA.await(); //Thread.sleep(1000); System.out.println(" end awaitA时间为 " + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName()); }catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } public void awaitB() { try { lock.lock(); System.out.println("begin awaitB时间为 " + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName()); conditionB.await(); //Thread.sleep(1000); System.out.println(" end awaitB时间为 " + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName()); }catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } public void signalAll_A() { try { lock.lock(); System.out.println(" signalAll_A时间为 " + System.currentTimeMillis() +" ThreadName=" + Thread.currentThread().getName()); conditionA.signalAll(); }catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void signalAll_B() { try { lock.lock(); System.out.println(" signalAll_B时间为 " + System.currentTimeMillis() +" ThreadName=" + Thread.currentThread().getName()); conditionB.signalAll(); }catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } } class MyThreadA extends Thread { private MyService service; public MyThreadA(MyService service) { this.service = service; } @Override public void run() { super.run(); service.awaitA(); } } class MyThreadB extends Thread { private MyService service; public MyThreadB(MyService service) { this.service = service; } @Override public void run() { super.run(); service.awaitB(); } }
begin awaitA时间为 1603982264116 ThreadName = A begin awaitB时间为 1603982264116 ThreadName = B signalAll_B时间为 1603982267131 ThreadName=main end awaitB时间为 1603982267131 ThreadName = B
使用ReentrantLock对象可以唤醒指定种类的线程,可以控制部分线程。
实现生产者/消费者模式:多对多交替打印
package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) { MyService1 myservice = new MyService1(); MyThreadA1[] threada = new MyThreadA1[10]; MyThreadB1[] threadb = new MyThreadB1[10]; for(int i = 0; i < 10; i++) { threada[i] = new MyThreadA1(myservice); threadb[i] = new MyThreadB1(myservice); threada[i].start(); threadb[i].start(); } } } class MyService1 { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); private boolean hasValue = false; public void set() { try { lock.lock(); while(hasValue == true) { System.out.println("有可能★★连续"); condition.await(); } System.out.println("打印★"); hasValue = true; condition.signalAll(); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); }finally { lock.unlock(); } } public void get() { try { lock.lock(); while(hasValue == false) { System.out.println("有可能☆☆连续"); condition.await(); } System.out.println("打印☆"); hasValue = false; condition.signalAll(); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); }finally { lock.unlock(); } } } class MyThreadA1 extends Thread { private MyService1 myservice; public MyThreadA1(MyService1 myservice) { super(); this.myservice = myservice; } @Override public void run() { super.run(); for(int i = 0; i < 10; i++) { myservice.set(); } } } class MyThreadB1 extends Thread { private MyService1 myservice; public MyThreadB1(MyService1 myservice) { super(); this.myservice = myservice; } @Override public void run() { super.run(); for(int i = 0; i < 10; i++) { myservice.get(); } } }
打印★ 有可能★★连续 有可能★★连续 打印☆ 有可能☆☆连续 打印★ 有可能★★连续 打印☆ 有可能☆☆连续 有可能☆☆连续 打印★ 有可能★★连续 打印☆ 有可能☆☆连续 有可能☆☆连续 打印★ 有可能★★连续 有可能★★连续 有可能★★连续 有可能★★连续 打印☆ 有可能☆☆连续 有可能☆☆连续 ...
为了避免死锁,将signal——>signalAll
公平锁与非公平锁
公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO的顺序;而非公平锁就是一种获取锁的抢占机制,是随机获得锁的,不一定先到先得,这种方式可能造成某县城一直拿不到锁,结果也就是不公平的。
/* * 公平锁 */ package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) { final Service service = new Service(true); //公平锁 MyThreadA1[] thread = new MyThreadA1[10]; for(int i = 0; i < 10; i++) { thread[i] = new MyThreadA1(service); } for(int i = 0; i < 10; i++) { thread[i].start(); } } } class Service { private ReentrantLock lock; public Service(boolean isFair) { super(); lock = new ReentrantLock(isFair); } public void serviceMethod() { try { lock.lock(); System.out.println("ThreadName = " + Thread.currentThread().getName() + "获得锁定"); }finally { lock.unlock(); } } } class MyThreadA1 extends Thread { private Service myservice ; public MyThreadA1(Service myservice) { this.myservice = myservice; } @Override public void run() { System.out.println("★线程" + Thread.currentThread().getName() + "运转了"); myservice.serviceMethod(); } } class MyThreadB1 extends Thread { private Service myservice ; public MyThreadB1(Service myservice) { this.myservice = myservice; } @Override public void run() { System.out.println("☆线程" + Thread.currentThread().getName() + "运转了"); myservice.serviceMethod(); } }
★线程Thread-1运转了 ★线程Thread-5运转了 ★线程Thread-4运转了 ★线程Thread-3运转了 ★线程Thread-0运转了 ★线程Thread-2运转了 ★线程Thread-9运转了 ★线程Thread-8运转了 ★线程Thread-7运转了 ThreadName = Thread-1获得锁定 ★线程Thread-6运转了 ThreadName = Thread-5获得锁定 ThreadName = Thread-4获得锁定 ThreadName = Thread-3获得锁定 ThreadName = Thread-0获得锁定 ThreadName = Thread-2获得锁定 ThreadName = Thread-9获得锁定 ThreadName = Thread-8获得锁定 ThreadName = Thread-7获得锁定 ThreadName = Thread-6获得锁定
打印结果基本是呈有序状态的,这就是公平锁的特点。
/* * 非公平锁 */ package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) { final Service service = new Service(false); //非公平锁 MyThreadA1[] thread = new MyThreadA1[10]; for(int i = 0; i < 10; i++) { thread[i] = new MyThreadA1(service); } for(int i = 0; i < 10; i++) { thread[i].start(); } } } class Service { private ReentrantLock lock; public Service(boolean isFair) { super(); lock = new ReentrantLock(isFair); } public void serviceMethod() { try { lock.lock(); System.out.println("ThreadName = " + Thread.currentThread().getName() + "获得锁定"); }finally { lock.unlock(); } } } class MyThreadA1 extends Thread { private Service myservice ; public MyThreadA1(Service myservice) { this.myservice = myservice; } @Override public void run() { System.out.println("★线程" + Thread.currentThread().getName() + "运转了"); myservice.serviceMethod(); } } class MyThreadB1 extends Thread { private Service myservice ; public MyThreadB1(Service myservice) { this.myservice = myservice; } @Override public void run() { System.out.println("☆线程" + Thread.currentThread().getName() + "运转了"); myservice.serviceMethod(); } }
★线程Thread-0运转了 ★线程Thread-4运转了 ★线程Thread-3运转了 ★线程Thread-2运转了 ★线程Thread-7运转了 ★线程Thread-1运转了 ★线程Thread-9运转了 ★线程Thread-8运转了 ★线程Thread-6运转了 ThreadName = Thread-0获得锁定 ★线程Thread-5运转了 ThreadName = Thread-5获得锁定 ThreadName = Thread-4获得锁定 ThreadName = Thread-3获得锁定 ThreadName = Thread-2获得锁定 ThreadName = Thread-7获得锁定 ThreadName = Thread-1获得锁定 ThreadName = Thread-9获得锁定 ThreadName = Thread-8获得锁定 ThreadName = Thread-6获得锁定
先启动start()的线程不代表先获得锁。
1)、方法getHoldCount():其作用是查询当前线程保持此锁定的个数,也就是调用lock()方法的次数。
package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) { Service service = new Service(); service.serviceMethod(); } } class Service { private ReentrantLock lock = new ReentrantLock(); public void serviceMethod() { try { lock.lock(); System.out.println("serviceMethod getHoldCount = " + lock.getHoldCount()); serviceMethod1(); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally { lock.unlock(); } } public void serviceMethod1() { try { lock.lock(); System.out.println("serviceMethod1 getHoldCount = " + lock.getHoldCount()); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally { lock.unlock(); } } }
serviceMethod getHoldCount = 1 serviceMethod1 getHoldCount = 2
2)、方法int getQueueLength()的作用是返回正等待获取此锁定的线程估计数,比如有5个线程,1个线程首先执行await()方法,那么在调用getQueueLength()方法后返回值是4,说明有4个线程同时在等待lock的释放。
/* * 公平锁 */ package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.serviceMethod(); } }; Thread[] threadArray = new Thread[10]; System.out.println("一共有10个线程!"); for(int i = 0; i < 10; i++) { threadArray[i] = new Thread(runnable); } for(int i = 0; i < 10; i++) { threadArray[i].start(); } Thread.sleep(2000); System.out.println("等待此锁定的线程数有:" + service.lock.getQueueLength()); } } class Service { public ReentrantLock lock = new ReentrantLock(); public void serviceMethod() { try { lock.lock(); System.out.println("ThreadName = " + Thread.currentThread().getName() + "进入方法!"); Thread.sleep(Integer.MAX_VALUE); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally { lock.unlock(); } } }
一共有10个线程! ThreadName = Thread-0进入方法! 等待此锁定的线程数有:9
3)方法int getWaitQueueLength(Condition condition)的作用是返回等待与此锁定相关的给定条件Condition的线程估计数。
package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.waitMethod(); } }; Thread[] threadArray = new Thread[10]; System.out.println("一共有10个线程!"); for(int i = 0; i < 10; i++) { threadArray[i] = new Thread(runnable); } for(int i = 0; i < 10; i++) { threadArray[i].start(); } Thread.sleep(2000); service.notifyMethod(); } } class Service { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void waitMethod() { try { lock.lock(); condition.await(); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally { lock.unlock(); } } public void notifyMethod() { try { lock.lock(); System.out.println("有 " + lock.getWaitQueueLength(condition) + "个线程正在等待condition"); condition.signal(); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); }finally { lock.unlock(); } } }
一共有10个线程! 有 10个线程正在等待condition
- boolean hasQueuedThread(Thread thread):的作用是查询指定的线程是否正在等待获得此锁定
- boolean hasQueuedThreads():查询是否有线程正在等待获取此锁定
package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override 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)); //由于threadA发生了睡眠,并且不释放锁;故threadB等待获得此锁定 System.out.println(service.lock.hasQueuedThread(threadB)); System.out.println(service.lock.hasQueuedThreads()); } } class Service { public ReentrantLock lock = new ReentrantLock(); public Condition condition = lock.newCondition(); public void waitMethod() { try { lock.lock(); Thread.sleep(Integer.MAX_VALUE); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally { lock.unlock(); } } }
false true true
方法boolean hasWaiters(Condition condition)的作用是查询是否有线程正在等待与此锁定有关的condtion条件。
/* * boolean hasWaiters(Condition condition):的作用是否有线程正在等待与此锁定有关的condition条件 * */ package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.waitMethod(); } }; Thread[] threadArray = new Thread[10]; for(int i=0; i<10; i++) { threadArray[i] = new Thread(runnable); } for(int i=0; i<10; i++) { threadArray[i].start(); } Thread.sleep(2000); service.notifyMethod(); } } 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) + "线程数是多少? " + lock.getWaitQueueLength(condition)); condition.signal(); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); }finally { lock.unlock(); } } }
有没有线程正在等待Condition?true线程数是多少? 10
4.1.12 方法isFair()、isHeldByCurrentThread()和isLocked()的测试
boolean isFair()的作用是判断是不是公平锁
/* * boolean hasWaiters(Condition condition):的作用是否有线程正在等待与此锁定有关的condition条件 */ package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) throws InterruptedException { final Service service = new Service(false); Runnable runnable = new Runnable() { @Override public void run() { service.serviceMethod(); } }; Thread thread = new Thread(runnable); thread.start(); } } class Service { private ReentrantLock lock = new ReentrantLock(); public Service(boolean isFair) { super(); lock = new ReentrantLock(isFair); } public void serviceMethod() { try { System.out.println("公平锁的情况:" + lock.isFair()); System.out.println("当前线程是否保持此锁定:" + lock.isHeldByCurrentThread()); lock.lock(); System.out.println("当前线程是否保持次锁定:" + lock.isHeldByCurrentThread()); }catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
公平锁的情况:false 当前线程是否保持此锁定:false 当前线程是否保持次锁定:true
方法boolean isLocked()的作用是查询此锁定是否由任意线程保持。
package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) throws InterruptedException { final Service service = new Service(false); Runnable runnable = new Runnable() { @Override public void run() { service.serviceMethod(); } }; Thread thread = new Thread(runnable); thread.start(); } } class Service { private ReentrantLock lock = new ReentrantLock(); public Service(boolean isFair) { super(); lock = new ReentrantLock(isFair); } public void serviceMethod() { try { System.out.println("此锁定是否由任意线程保持:" + lock.isLocked()); lock.lock(); System.out.println("此锁定是否由任意线程保持:" + lock.isLocked()); }catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
此锁定是否由任意线程保持:false 此锁定是否由任意线程保持:true
4.1.13 方法lockInterruptibly()、tryLock()和tryLock(long timeout, TimeUnit unit)
/* * void lockInterruptibly() 如果当前线程未被中断,则获取锁定,如果已经被中断则出现异常; 相反void lock() 如果当前线程被interrupt中断了,lock()则不出现异常 */ package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.waitMethod(); } }; Thread thread = new Thread(runnable); thread.setName("A"); thread.start(); Thread.sleep(5000); Thread threadB = new Thread(runnable); threadB.setName("B"); threadB.start(); threadB.interrupt(); System.out.println("main end!"); } } class Service { public ReentrantLock lock = new ReentrantLock(); public Condition condition = lock.newCondition(); public void waitMethod() { try { lock.lockInterruptibly(); System.out.println("lock begin " + Thread.currentThread().getName()); for(int i=0; i<Integer.MAX_VALUE / 10; i++) { String newString = new String(); Math.random(); } System.out.println("lock end" + Thread.currentThread().getName()); }catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
lock begin A lock endA main end! java.lang.InterruptedException at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(Unknown Source) at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(Unknown Source) at ReentrantLock.Service.waitMethod(t2.java:38) at ReentrantLock.t2$1.run(t2.java:15) at java.lang.Thread.run(Unknown Source) Exception in thread "B" java.lang.IllegalMonitorStateException at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source) at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source) at java.util.concurrent.locks.ReentrantLock.unlock(Unknown Source) at ReentrantLock.Service.waitMethod(t2.java:51) at ReentrantLock.t2$1.run(t2.java:15) at java.lang.Thread.run(Unknown Source)
方法 boolean tryLock()的作用是,仅在调用时,锁定未被另一个线程保持的情况下,才获取该锁定。
/* * void lockInterruptibly() 如果当前线程未被中断,则获取锁定,如果已经被中断则出现异常; 相反void lock() 如果当前线程被interrupt中断了,lock()则不出现异常 */ package ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { service.waitMethod(); } }; Thread thread = new Thread(runnable); thread.setName("A"); thread.start(); Thread.sleep(5000); Thread threadB = new Thread(runnable); threadB.setName("B"); threadB.start(); } } class Service { public ReentrantLock lock = new ReentrantLock(); public void waitMethod() { if(lock.tryLock()) { System.out.println("锁定未被保持 " + Thread.currentThread().getName() + "获得锁"); }else { System.out.println("锁定被保持 " + Thread.currentThread().getName() + "没有获得锁"); } } }
锁定未被保持 A获得锁 锁定被保持 B没有获得锁
boolean tryLock(long timeout, TimeUnit unit)的作用是,如果锁定在等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定,且返回true;
package ReentrantLock; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) throws InterruptedException { final Service service = new Service(); Runnable runnable = new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "调用waitMethod时间:" + System.currentTimeMillis()); service.waitMethod(); } }; Thread thread = new Thread(runnable); thread.setName("A"); thread.start(); Thread threadB = new Thread(runnable); threadB.setName("B"); threadB.start(); } } class Service { public ReentrantLock lock = new ReentrantLock(); public void waitMethod() { try { if(lock.tryLock(3, TimeUnit.SECONDS)) { System.out.println(" " + Thread.currentThread().getName() + "获得锁的时间: " + System.currentTimeMillis()); Thread.sleep(10000); }else { System.out.println(" " + Thread.currentThread().getName() + "没有获得锁"); } }catch (Exception e) { // TODO: handle exception e.printStackTrace(); }finally { if(lock.isHeldByCurrentThread()) { lock.unlock(); } } } }
A调用waitMethod时间:1604308949222 B调用waitMethod时间:1604308949222 A获得锁的时间: 1604308949223 B没有获得锁
awaitUninterruptibly()方法和await()方法的区别
- 线程调用condition.await()方法后,线程处于await状态,此时若在调用thread.interrupt(),会报错!
- 而线程调用condition.awaitUninterruptibly()方法后,再调用thread.interrupt()则不会报错!
情况1
package ReentrantLock; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) throws InterruptedException { try { Service service = new Service(); MyThread thread = new MyThread(service); thread.start(); Thread.sleep(3000); thread.interrupt(); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } } class Service { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void testMethod() { try { lock.lock(); System.out.println("wait begin!"); condition.await(); System.out.println("wait end!"); }catch (Exception e) { e.printStackTrace(); System.out.println("catch"); }finally { lock.unlock(); } } } class MyThread extends Thread { private Service service; public MyThread(Service service) { super(); this.service = service; } @Override public void run() { // TODO 自动生成的方法存根 super.run(); service.testMethod(); } }
wait begin! java.lang.InterruptedException catch at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(Unknown Source) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source) at ReentrantLock.Service.testMethod(t2.java:31) at ReentrantLock.MyThread.run(t2.java:55)
情况2
package ReentrantLock; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) throws InterruptedException { try { Service service = new Service(); MyThread thread = new MyThread(service); thread.start(); Thread.sleep(3000); thread.interrupt(); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } } class Service { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void testMethod() { try { lock.lock(); System.out.println("wait begin!"); condition.awaitUninterruptibly(); System.out.println("wait end!"); }catch (Exception e) { e.printStackTrace(); System.out.println("catch"); }finally { lock.unlock(); } } } class MyThread extends Thread { private Service service; public MyThread(Service service) { super(); this.service = service; } @Override public void run() { // TODO 自动生成的方法存根 super.run(); service.testMethod(); } }
wait begin!
从打印信息看,condition.awaitUninterruptibly() 不会报错
4.1.15 方法awaitUntil()的使用
awaitUntil(Date deadline):当前线程进入等待状态直到被通知,中断或者到了某个时间deadline。
package ReentrantLock; import java.util.Calendar; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) throws InterruptedException { try { Service service = new Service(); MyThread thread = new MyThread(service); thread.start(); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } } class Service { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void waitMethod() { try { Calendar calendarRef = Calendar.getInstance(); //获得一个Calendar类型的对象 calendarRef.add(Calendar.SECOND, 10); lock.lock(); System.out.println("wait begin timer = " + System.currentTimeMillis()); condition.awaitUntil(calendarRef.getTime()); System.out.println("wait end timer = " + System.currentTimeMillis()); }catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void notifyMethod() { try { Calendar calendarRef = Calendar.getInstance(); calendarRef.add(Calendar.SECOND, 10); lock.lock(); System.out.println("notify begin timer = " + System.currentTimeMillis()); condition.signalAll(); System.out.println("notify end timer = " + System.currentTimeMillis()); }catch (Exception e) { e.printStackTrace(); System.out.println("catch"); }finally { lock.unlock(); } } } class MyThread extends Thread { private Service service; public MyThread(Service service) { super(); this.service = service; } @Override public void run() { // TODO 自动生成的方法存根 super.run(); service.waitMethod(); } } class MyThread1 extends Thread { private Service service; public MyThread1(Service service) { super(); this.service = service; } @Override public void run() { // TODO 自动生成的方法存根 super.run(); service.notifyMethod(); } }
wait begin timer = 1604391980471 wait end timer = 1604391990461
从打印信息可以看出,线程到了deadline,就自动唤醒,可以没有notify()。
当然线程在等待时间到达前,可以被其他线程提前唤醒。
package ReentrantLock; import java.util.Calendar; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class t2 { public static void main(String[] args) throws InterruptedException { try { Service service = new Service(); MyThread thread = new MyThread(service); thread.start(); Thread.sleep(2000); MyThread1 thread1 = new MyThread1(service); thread1.start(); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } } class Service { private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void waitMethod() { try { Calendar calendarRef = Calendar.getInstance(); //获得一个Calendar类型的对象 calendarRef.add(Calendar.SECOND, 10); lock.lock(); System.out.println("wait begin timer = " + System.currentTimeMillis()); condition.awaitUntil(calendarRef.getTime()); System.out.println("wait end timer = " + System.currentTimeMillis()); }catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void notifyMethod() { try { Calendar calendarRef = Calendar.getInstance(); calendarRef.add(Calendar.SECOND, 10); lock.lock(); System.out.println("notify begin timer = " + System.currentTimeMillis()); condition.signalAll(); System.out.println("notify end timer = " + System.currentTimeMillis()); }catch (Exception e) { e.printStackTrace(); System.out.println("catch"); }finally { lock.unlock(); } } } class MyThread extends Thread { private Service service; public MyThread(Service service) { super(); this.service = service; } @Override public void run() { // TODO 自动生成的方法存根 super.run(); service.waitMethod(); } } class MyThread1 extends Thread { private Service service; public MyThread1(Service service) { super(); this.service = service; } @Override public void run() { // TODO 自动生成的方法存根 super.run(); service.notifyMethod(); } }
wait begin timer = 1604392229770 notify begin timer = 1604392231757 notify end timer = 1604392231757 wait end timer = 1604392231757
可见线程thread被线程thread1唤醒了,不过要等唤醒线程运行完后,thread才能继续执行 System.out.println("wait end timer = " + System.currentTimeMillis());
如果设置的sleep() 等待时间 超过deadline,那么thread就自动唤醒,打印结果就如下:
wait begin timer = 1604392400427 wait end timer = 1604392410415 notify begin timer = 1604392420410 notify end timer = 1604392420410
作者:Ryanjie
出处:http://www.cnblogs.com/ryanjan/
本文版权归作者和博客园所有,欢迎转载。转载请在留言板处留言给我,且在文章标明原文链接,谢谢!
如果您觉得本篇博文对您有所收获,觉得我还算用心,请点击右下角的 [推荐],谢谢!