在上一篇中,我们学习了JDK并发包的重入锁的使用,然而线程流程的处理,并不单单是上锁,中断的操作,还有之前学到过的等待wait(),通知notify()等等,但wait(),notify()是与synchronized()搭配使用的。对应于jdk并发包,我们也有相应的类去使用,那就是重入锁的好搭档——Condition接口。
Condition接口有以下方法:
public interface Condition {
void await() throws InterruptedException;
void awaitUninterruptibly();
long awaitNanos(long var1) throws InterruptedException;
boolean await(long var1, TimeUnit var3) throws InterruptedException;
boolean awaitUntil(Date var1) throws InterruptedException;
void signal();
void signalAll();
}
Condition的特性:
- Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。不同的是,Object中的这些方法是和同步锁捆绑使用的;而Condition是需要与互斥锁/共享锁捆绑使用的。
- Condition它更强大的地方在于:能够更加精细的控制多线程的休眠与唤醒。对于同一个锁,我们可以创建多个Condition,在不同的情况下使用不同的Condition。
例如,假如多线程读/写同一个缓冲区:当向缓冲区中写入数据之后,唤醒"读线程";当从缓冲区读出数据之后,唤醒"写线程";并且当缓冲区满的时候,"写线程"需要等待;当缓冲区为空时,"读线程"需要等待。 - 如果采用Object类中的wait(), notify(), notifyAll()实现该缓冲区,当向缓冲区写入数据之后需要唤醒"读线程"时,不可能通过notify()或notifyAll()明确的指定唤醒"读线程",而只能通过notifyAll唤醒所有线程(但是notifyAll无法区分唤醒的线程是读线程,还是写线程)。 但是,通过Condition,就能明确的指定唤醒读线程。
注:建议查看之前的文章去了解下wait和notify的使用,后续对Condition的使用是很有帮助的。
Condition的使用(Condition是需要配合重入锁使用的)
举个例子:
package stop_demo;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 例子说明:
* add()方法:当集合长度为10时,就挂起当前的线程, 让其他线程先走。否则就会添加一条信息,然后唤起执行sub()的线程
* sub()方法:当长度为0时,同理操作
*
* @author fei
*
*/
public class Condition_demo implements Runnable {
private final static Lock lock = new ReentrantLock();
private final static Condition addCondition = lock.newCondition();
private final static Condition subCondition = lock.newCondition();
private static int num = 0;
private static List<String> lists = new LinkedList<String>();
private boolean flag;
public Condition_demo(boolean flag){
this.flag=flag;
}
@Override
public void run() {
if (flag) {
add();//执行线程添加器
}
else {
sub();//执行线程减数器
}
}
public void add() {
lock.lock();
try {
while(lists.size() == 10) {//当集合已满,则"添加"线程等待
addCondition.await();//满了就挂起来
}
num++;
lists.add("add Banana" + num);
System.out.println("处于‘增加’线程方法 集合长度为: " + lists.size());
System.out.println("The Current Thread is " + Thread.currentThread().getName());
System.out.println("==============================");
this.subCondition.signal();//唤起“减少”线程
} catch (InterruptedException e) {
e.printStackTrace();
} finally {//释放锁
lock.unlock();
}
}
public void sub() {
lock.lock();
try {
while(lists.size() == 0) {//当集合为空时,"减少"线程等待
System.out.println("‘减少’线程已挂起~~~~");
subCondition.await();
}
String str = lists.get(0);
lists.remove(0);
System.out.println("处于‘减少’线程方法: 集合内容为: [" + str + "]");
System.out.println("The Current Thread is " + Thread.currentThread().getName());
System.out.println("==============================");
num--;
addCondition.signal();//唤起“增加”线程
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
Condition_demo task1 = new Condition_demo(true);
Condition_demo task2 = new Condition_demo(false);
Thread t1 = new Thread(task1);
Thread t2 = new Thread(task1);
Thread t3 = new Thread(task1);
Thread t4 = new Thread(task1);
Thread t5 = new Thread(task1);
Thread t7 = new Thread(task2);
Thread t6 = new Thread(task2);
Thread t8 = new Thread(task2);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
t8.start();
}
}
可以复制当前例子到demo中,执行后就会发现,condition和lock真是个好搭档!!