condition和Lock锁一样出现在jdk1.5中的,它的出现使用来替代传统的Object的wait()/notify()方法,配合Lock锁实现线程间的协作的。
java.util.concurrent.locks包下常用的类与接口(jdk1.5中):
Lock 和 Thread 三者之间的关系如下图:
Condition中主要的方法包括:await()/signal(),它们分别对应Object中的wait()/notify()方法,Condition相比较Object方法提供了更安全、高效和灵活的线程间协作,condition依赖与Lock接口,condition通过Lock.newCondition创建,同时,Condition必须在Lock的保护内使用。在多线程的状态下,可以通过以condition实例为单位的通知等待机制的分组,只通知部分线程。
condition分组实例:
// 线程 A class ThreadA extends Thread { private MyService service; public ThreadA(MyService service) { super(); this.service = service; } @Override public void run() { service.awaitA(); } } // 线程 B class ThreadB extends Thread { private MyService service; public ThreadB(MyService service) { super(); this.service = service; } @Override public void run() { service.awaitB(); } } class MyService { private Lock lock = new ReentrantLock(); // 使用多个Condition实现通知部分线程 public Condition conditionA = lock.newCondition(); public Condition conditionB = lock.newCondition(); public void awaitA() { lock.lock(); try { System.out.println("begin awaitA时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionA.await(); System.out.println(" end awaitA时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void awaitB() { lock.lock(); try { System.out.println("begin awaitB时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionB.await(); 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(); } finally { lock.unlock(); } } public void signalAll_B() { try { lock.lock(); System.out.println(" signalAll_B时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionB.signalAll(); } finally { lock.unlock(); } } } public class ConditionTest { public static void main(String[] args) throws InterruptedException { MyService service = new MyService(); ThreadA a = new ThreadA(service); a.setName("A"); a.start(); ThreadB b = new ThreadB(service); b.setName("B"); b.start(); Thread.sleep(3000); service.signalAll_A(); } }
输出结果:
begin awaitA时间为1615804726283 ThreadName=A
begin awaitB时间为1615804726284 ThreadName=B
signalAll_A时间为1615804729284 ThreadName=main
end awaitA时间为1615804729284 ThreadName=A
我们可以看到只有A组被唤醒了,而B组依旧处于阻塞状态;
假如:我们使用一个condition实例进行线程间的协作会怎么样?
实例:
package thread; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class ThreadE extends Thread{ private MySingleService service; public ThreadE(MySingleService service) { super(); this.service = service; } @Override public void run() { service.awaitE(); } } class ThreadF extends Thread{ private MySingleService service; public ThreadF(MySingleService service) { super(); this.service = service; } @Override public void run() { service.awaitF(); } } class MySingleService{ private Lock lock = new ReentrantLock(); // 使用多个Condition实现通知部分线程 public Condition conditionE = lock.newCondition(); public void awaitE() { lock.lock(); try { System.out.println("begin awaitA时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionE.await(); System.out.println(" end awaitA时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void awaitF() { lock.lock(); try { System.out.println("begin awaitB时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionE.await(); System.out.println(" end awaitB时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signalAll_E() { try { lock.lock(); System.out.println(" signalAll_A时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionE.signalAll(); } finally { lock.unlock(); } } } public class SingleConditionTest { public static void main(String[] args) throws InterruptedException { MySingleService service = new MySingleService(); ThreadE e = new ThreadE(service); e.setName("E"); e.start(); ThreadF f = new ThreadF(service); f.setName("F"); f.start(); Thread.sleep(3000); service.signalAll_E(); } }
输出结果:
begin awaitA时间为1615804861481 ThreadName=E
begin awaitB时间为1615804861482 ThreadName=F
signalAll_A时间为1615804864482 ThreadName=main
end awaitA时间为1615804864482 ThreadName=E
end awaitB时间为1615804864482 ThreadName=F
我们发现两组线程都被唤醒了,所以Condition的分组机制是按照Condition实例来进行的;
同样,相比较Condition,Object提供的wait()/notify()方法也只能在synchronized,以下为对照组实例:
实例:
class ThreadC extends Thread{ private MyObjectService service; public ThreadC(MyObjectService service) { super(); this.service = service; } @Override public void run() { service.waitC(); } } class ThreadD extends Thread{ private MyObjectService service; public ThreadD(MyObjectService service) { super(); this.service = service; } @Override public void run() { service.waitD(); } } class MyObjectService{ public synchronized void waitC() { try { System.out.println("begin awaitC时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); this.wait(); System.out.println(" end awaitC时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void waitD() { try { System.out.println("begin awaitD时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); this.wait(); System.out.println(" end awaitD时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void notifyAll_C() { try { System.out.println(" notifyAll_C时间为:" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); this.notifyAll(); } catch (Exception e) { e.printStackTrace(); } } } public class ObjectThreadTest { public static void main(String[] args) throws InterruptedException { MyObjectService service = new MyObjectService(); ThreadC c = new ThreadC(service); c.setName("C"); c.start(); ThreadD d = new ThreadD(service); d.setName("D"); d.start(); Thread.sleep(3000); service.notifyAll_C(); } }
输出结果:
begin awaitC时间为1615804981351 ThreadName=C
begin awaitD时间为1615804981352 ThreadName=D
notifyAll_C时间为:1615804984353 ThreadName=main
end awaitD时间为1615804984353 ThreadName=D
end awaitC时间为1615804984353 ThreadName=C