Lock中使用Condition实现等待通知
- Condition类有很好的灵活性,可以实现多路通知功能,一个Lock对象中可以创建多个Condition对象实例,线程对象可以注册在指定的Condition中,进而有选择的进行线程通知,在调度线程上更加灵活
- wait与notify/notifyAll进行等待通知时,被通知的线程是随机的,但是Condition与Lock结合的通知是有选择性的通知
- synchronized就相当于整个Lock对象中只有一个单一的Condition对象,所有线程对象都注册在一个Condition对象身上,线程开始notifyAll时,需要通知所有的WAITING线程,没有选择性,会出现很大的效率问题
1 public class MyService { 2 private Lock lock = new ReentrantLock(); 3 public Condition condition = lock.newCondition(); 4 public void await(){ 5 try { 6 lock.lock(); 7 System.out.println("await时间为"+System.currentTimeMillis()); 8 condition.await(); 9 } catch (InterruptedException e) { 10 e.printStackTrace(); 11 } finally { 12 lock.unlock(); 13 } 14 } 15 16 public void signal(){ 17 try { 18 lock.lock(); 19 System.out.println("signal时间为"+System.currentTimeMillis()); 20 condition.signal(); 21 } finally { 22 lock.unlock(); 23 } 24 } 25 }
1 public class MyThread extends Thread { 2 private MyService service; 3 4 public MyThread(MyService service) { 5 this.service = service; 6 } 7 8 @Override 9 public void run() { 10 service.await(); 11 } 12 }
1 public class Run { 2 public static void main(String[] args) { 3 try { 4 MyService service = new MyService(); 5 MyThread mt = new MyThread(service); 6 mt.start(); 7 Thread.sleep(3000); 8 service.signal(); 9 } catch (InterruptedException e) { 10 e.printStackTrace(); 11 } 12 } 13 }
-------------------------------------------------------打印输出-------------------------------------------------------
await时间为1537949157830
signal时间为1537949160830
Condition类中的await方法相当于Object类中的wait方法
Condition类中的signal/signalAll方法相当于Object类中的notify/notifyAll方法
案例2
1 public class MyService { 2 private Lock lock = new ReentrantLock(); 3 public Condition condition = lock.newCondition(); 4 5 public void awaitA(){ 6 try { 7 lock.lock(); 8 System.out.println("begin awaitA时间为"+System.currentTimeMillis()+ " ThreadName="+Thread.currentThread().getName()); 9 condition.await(); 10 System.out.println("end awaitA时间为"+System.currentTimeMillis()+ " ThreadName="+Thread.currentThread().getName()); 11 } catch (InterruptedException e) { 12 e.printStackTrace(); 13 } finally { 14 lock.unlock(); 15 16 } 17 } 18 19 public void awaitB(){ 20 try { 21 lock.lock(); 22 System.out.println("begin awaitB时间为"+System.currentTimeMillis()+ " ThreadName="+Thread.currentThread().getName()); 23 condition.await(); 24 System.out.println("end awaitB时间为"+System.currentTimeMillis()+ " ThreadName="+Thread.currentThread().getName()); 25 } catch (InterruptedException e) { 26 e.printStackTrace(); 27 } finally { 28 lock.unlock(); 29 } 30 } 31 32 public void signalAll(){ 33 try { 34 lock.lock(); 35 System.out.println("signalAll时间为"+System.currentTimeMillis()+ " ThreadName="+Thread.currentThread().getName()); 36 condition.signalAll(); 37 } finally { 38 lock.unlock(); 39 } 40 } 41 }
线程
1 public class ThreadA extends Thread { 2 private MyService service; 3 4 public ThreadA(MyService service) { 5 this.service = service; 6 } 7 8 @Override 9 public void run() { 10 service.awaitA(); 11 } 12 } 13 ------------------------------------------------- 14 public class ThreadB extends Thread { 15 private MyService service; 16 17 public ThreadB(MyService service) { 18 this.service = service; 19 } 20 21 @Override 22 public void run() { 23 service.awaitB(); 24 } 25 }
1 public class Run { 2 public static void main(String[] args) throws InterruptedException { 3 MyService service = new MyService(); 4 ThreadA a = new ThreadA(service); 5 a.setName("A"); 6 ThreadB b = new ThreadB(service); 7 b.setName("B"); 8 a.start(); 9 b.start(); 10 Thread.sleep(3000); 11 service.signalAll(); 12 } 13 }
-------------------------------------------------------打印输出-------------------------------------------------------
begin awaitA时间为1537951494924 ThreadName=A begin awaitB时间为1537951494925 ThreadName=B signalAll时间为1537951497924 ThreadName=main end awaitA时间为1537951497924 ThreadName=A end awaitB时间为1537951497925 ThreadName=B
线程A和B都被唤醒了
使用多个Condition实现通知部分线程
想要单独唤醒部分线程,就需要使用多个Condition对象,先对线程进行分组,Condition对象可以唤醒部分指定线程,有助于提高程序运行效率
1 public class MyService { 2 private Lock lock = new ReentrantLock(); 3 public Condition conditionA = lock.newCondition(); 4 public Condition conditionB = lock.newCondition(); 5 6 public void awaitA(){ 7 try { 8 lock.lock(); 9 System.out.println("begin awaitA时间为"+System.currentTimeMillis()+" ThreadName="+Thread.currentThread().getName()); 10 conditionA.await(); 11 System.out.println("--end awaitA时间为"+System.currentTimeMillis()+" ThreadName="+Thread.currentThread().getName()); 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } finally { 15 lock.unlock(); 16 } 17 } 18 19 public void awaitB(){ 20 try { 21 lock.lock(); 22 System.out.println("begin awaitB时间为"+System.currentTimeMillis()+" ThreadName="+Thread.currentThread().getName()); 23 conditionB.await(); 24 System.out.println("--end awaitB时间为"+System.currentTimeMillis()+" ThreadName="+Thread.currentThread().getName()); 25 } catch (InterruptedException e) { 26 e.printStackTrace(); 27 } finally { 28 lock.unlock(); 29 } 30 } 31 32 public void signAll_A(){ 33 try { 34 lock.lock(); 35 System.out.println("signAll_A时间为"+System.currentTimeMillis()+" ThreadName="+Thread.currentThread().getName()); 36 conditionA.signalAll(); 37 } finally { 38 lock.unlock(); 39 } 40 } 41 42 public void signAll_B(){ 43 try { 44 lock.lock(); 45 System.out.println("signAll_B时间为"+System.currentTimeMillis()+" ThreadName="+Thread.currentThread().getName()); 46 conditionB.signalAll(); 47 } finally { 48 lock.unlock(); 49 } 50 } 51 }
线程
1 public class ThreadA extends Thread { 2 private MyService service; 3 4 public ThreadA(MyService service) { 5 this.service = service; 6 } 7 8 @Override 9 public void run() { 10 service.awaitA(); 11 } 12 } 13 ----------------------------------------------- 14 public class ThreadB extends Thread { 15 private MyService service; 16 17 public ThreadB(MyService service) { 18 this.service = service; 19 } 20 21 @Override 22 public void run() { 23 service.awaitB(); 24 } 25 }
1 public class Run { 2 public static void main(String[] args) throws InterruptedException { 3 MyService service = new MyService(); 4 ThreadA a = new ThreadA(service); 5 a.setName("A"); 6 ThreadB b = new ThreadB(service); 7 b.setName("B"); 8 a.start(); 9 b.start(); 10 Thread.sleep(3000); 11 service.signAll_A(); 12 } 13 }
-------------------------------------------------------打印输出-------------------------------------------------------
begin awaitA时间为1537952328573 ThreadName=A begin awaitB时间为1537952328573 ThreadName=B signAll_A时间为1537952331572 ThreadName=main --end awaitA时间为1537952331572 ThreadName=A
线程A被唤醒了,但是线程B仍然在等待