Condition
实例实质上被绑定到一个锁上。要为特定 Lock
实例获得 Condition
实例,使用其 newCondition()
方法。
Condition
将 Object
监视器方法(wait
、notify
和 notifyAll
)分解成截然不同的对象,以便通过将这些对象与任意 Lock
实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock
替代了 synchronized
方法和语句的使用,Condition
替代了 Object 监视器方法的使用。
下面使用condition的await和singal方法可以替代object的wait和notify方法,lock锁替代了synchronized方法块,实例代码如下:
public void init() {
Business business = new Business();
// 子线程
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 50; i++) {business.sub(i);}
}
}).start();
// 主线程
for (int j = 0; j < 50; j++) {business.main(j);}
}
class Business {
boolean isSub = true;
public void main(int n) {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();
try {
if (isSub) {condition.await();}
for (int i = 0; i < 7; i++) {
System.out.println("main ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次");
}
System.out.println();
isSub = true;
condition.signal();
} catch (Exception e) {
lock.unlock();
}
}
public void sub(int n) {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();
try {
if (!isSub) {condition.await();}
for (int i = 0; i < 13; i++) {
System.out.println("sub ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次");
}
System.out.println();
isSub = false;
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
condition不仅可以替代object的wait和notify方法,可以实现多路复用的功能,废话少说先上代码:
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length)
putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length)
takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
作为一个示例,假定有一个绑定的缓冲区,它支持 put
和 take
方法。如果试图在空的缓冲区上执行 take
操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put
操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待 set 中保存 put
线程和 take
线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition
实例来做到这一点。
注意,Condition
实例只是一些普通的对象,它们自身可以用作 synchronized
语句中的目标,并且可以调用自己的 wait
和 notification
监视器方法。获取 Condition
实例的监视器锁或者使用其监视器方法,与获取和该 Condition
相关的 Lock
或使用其 waiting
和 signalling
方法没有什么特定的关系。为了避免混淆,建议除了在其自身的实现中之外,切勿以这种方式使用 Condition
实例。
除非另行说明,否则为任何参数传递 null
值将导致抛出 NullPointerException
。
此外,提供一个第一个实例代码的升级,让三个线程有序的各执行20次。
public void init() {
Business business = new Business();
// 子线程
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {business.sub(i);}
}
}).start();
// 次子线程
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {business.subSub(i);}
}
}).start();
// 主线程
for (int j = 0; j < 20; j++) {business.main(j);}
}
class Business {
int flag=0;
Lock lock = new ReentrantLock();
Condition condition0 = lock.newCondition();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
public void main(int n) {
lock.lock();
try {
if (flag!=0) {condition0.await();}
for (int i = 0; i < 7; i++) {
System.out.println("main ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次");
}
System.out.println();
flag=1;
condition1.signal();
} catch (Exception e) {
lock.unlock();
}
}
public void sub(int n) {
lock.lock();
try {
if (flag!=1) {condition1.await();}//
for (int i = 0; i < 13; i++) {
System.out.println("sub ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次");
}
System.out.println();
flag = 2;
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void subSub(int n) {
lock.lock();
try {
if (flag!=2) {condition2.await();}//
for (int i = 0; i < 23; i++) {
System.out.println("sub--Sub ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次");
}
System.out.println();
flag = 0;
condition0.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
new ThreeLockContidion2().init();
}