java中条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是通过一个Lock对象上调用newCondition()方法来获取的,这样,条件就和一个锁对象绑定起来了。因此,Java中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全。
条件变量的出现是为了更精细控制线程等待与唤醒,在Java5之前,线程的等待与唤醒依靠的是Object对象的wait()和notify()/notifyAll()方法,这样的处理不够精细,如不能精确指定唤醒哪个线程。
通熟易懂的说,就是消费者/生产者的场景中,在原来的基础上,增加了队列满时及时通知消费者,队列空时及时通知生产者的优化,通常是两个条件变量一起出现,一个控制值,但两个条件变量可以毫无关系,终归来说还是在Lock的范围内。所以,从本质上来说,是对Object监视器的场景性优化,而不是全新机制的引入。
而在Java5中,一个锁可以有多个条件,每个条件上可以有多个线程等待,通过调用await()方法,可以让线程在该条件下等待。当调用signalAll()方法,又可以唤醒该条件下的等待的线程。
案例:定义三个任务类A、B、C分别含有方法a()、b()、c()并分别循环打印结果"a"、"b"、"c",启动三个线程分别执行A、B、C类中的a()、b()、c()并打印出结果。
a
b
c
a
b
c
a
b
c
a
b
c
......
使用传统的wait()、notify()方法,接合synchronized关键字实现 缺点:不能指定唤醒哪个线程,
package cn.itcats.thread.Condition1;
import cn.itcats.thread.Condition1.Condition1.B.C;
//顺序打印abcabc————使用线程之间的通信技术
public class Condition1 {
private int signal = 0;
public synchronized void a() {
while(signal != 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("a");
signal++;
notifyAll();
}
public synchronized void b() {
while(signal != 1) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("b");
signal++;
notifyAll();
}
public synchronized void c() {
while(signal != 2) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("c");
signal = 0;
notifyAll();
}
public static void main(String[] args) {
Condition1 condition1 = new Condition1();
A a = new A(condition1);
B b = new B(condition1);
C c = new C(condition1);
new Thread(a).start();
new Thread(b).start();
new Thread(c).start();
}
static class A implements Runnable {
private Condition1 condition1;
public A(Condition1 condition1) {
this.condition1 = condition1;
}
public void run() {
while (true) {
condition1.a();
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class B implements Runnable {
private Condition1 condition1;
public B(Condition1 condition1) {
this.condition1 = condition1;
}
public void run() {
while (true) {
condition1.b();
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class C implements Runnable {
private Condition1 condition1;
public C(Condition1 condition1) {
this.condition1 = condition1;
}
public void run() {
while (true) {
condition1.c();
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
使用Condition接口中await()和signal()实现,接合Lock接口
1、把synchronized该换成Lock接口的lock()和unlock()实现
2、控制3个方法的条件,则创建3个Condition接口对象
3、把wait()方法改换成await(),把notify()方法该换成 被唤醒的Condition对象.signal()
package cn.itcats.thread.Condition2;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import cn.itcats.thread.Condition2.Condition1.B.C;
//顺序打印abcabc————使用线程之间的通信技术
public class Condition1 {
private int signal = 0;
Lock lock = new ReentrantLock();
Condition a = lock.newCondition();
Condition b = lock.newCondition();
Condition c = lock.newCondition();
//删除synchronized关键字,改用Lock
public void a() {
lock.lock();
while(signal != 0) {
try {
a.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("a");
signal++;
//唤醒b
b.signal();
lock.unlock();
}
public void b() {
lock.lock();
while(signal != 1) {
try {
b.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("b");
signal++;
c.signal();
lock.unlock();
}
public void c() {
lock.lock();
while(signal != 2) {
try {
c.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("c");
signal = 0;
a.signal();
lock.unlock();
}
public static void main(String[] args) {
Condition1 condition1 = new Condition1();
A a = new A(condition1);
B b = new B(condition1);
C c = new C(condition1);
new Thread(a).start();
new Thread(b).start();
new Thread(c).start();
}
static class A implements Runnable {
private Condition1 condition1;
public A(Condition1 condition1) {
this.condition1 = condition1;
}
public void run() {
while (true) {
condition1.a();
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class B implements Runnable {
private Condition1 condition1;
public B(Condition1 condition1) {
this.condition1 = condition1;
}
public void run() {
while (true) {
condition1.b();
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class C implements Runnable {
private Condition1 condition1;
public C(Condition1 condition1) {
this.condition1 = condition1;
}
public void run() {
while (true) {
condition1.c();
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
如何获取Condition对象和Condition接口的实现类
//如何获取Condition对象,ReentrantLock源码中newCondition()方法
public Condition newCondition() {
return sync.newCondition();
}
//顺着源码找到Sync类中的newCondition()方法
final ConditionObject newCondition() {
//说明了Condition接口的有且只有一个实现类就是ConditionObject
return new ConditionObject();
}
//而ConditionObject又是AQS类中的一个内部类
//空参构造 public ConditionObject() { }
//关注ConditionObject中的await()和signal()方法
//ConditionObject中的 await()方法
public final void await() throws InterruptedException {
//1、若线程中断则抛出线程中断异常,则无需等待await()
if (Thread.interrupted())
throw new InterruptedException();
//2、添加到等待队列,如果lastWaiter是cancel状态,那么会把它踢出Condition队列
Node node = addConditionWaiter();
//3、调用tryRelease,释放线程所获取的lock
int savedState = fullyRelease(node);
int interruptMode = 0;
//4、判断node是否在同步器的队列中
while (!isOnSyncQueue(node)) {
//若不在同步队列,park()和unpark()方法实现阻塞线程和解除线程阻塞
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
//自旋等待尝试再次获取锁,调用acquireQueued方法
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
//signal()源码解析
public final void signal() {
//判断是否为独占锁
if (!isHeldExclusively())
//如果不是独占锁则抛出异常
throw new IllegalMonitorStateException();
Node first = firstWaiter;
//第一个节点不为空
if (first != null)
doSignal(first);
}