深知身在情长在,怅望江头江水声
此前,我们知道用synchronized与wait()和notify()/notifyAll()方法结合可以实现等待/通知模式。但是,在使用notify()/notifyAll()方法进行通知时,被通知的线程却是由JVM随机选择的。为了摆脱这种窘境,Java在1.5引入了ReentrantLock和Condition类结合使用来达到有选择性的进行线程通知,在调度线程上更加灵活。下面是个测试方法:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test {
private Lock lock = new ReentrantLock();
public Condition condition = lock.newCondition();
//等待
public void await() {
try {
lock.lock(); //调用lock.lock()方法的线程就持有了"对象监视器",其他线程只有等待锁被释放时再次争抢
System.out.println("await()时间为:" + System.currentTimeMillis());
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//通知
public void signal() {
try {
lock.lock();
System.out.println("signal()时间为:" + System.currentTimeMillis());
condition.signal();
} finally {
lock.unlock();
}
}
}
//线程类
class ThreadA extends Thread {
private Test test;
public ThreadA(Test test) {
super();
this.test = test;
}
@Override
public void run() {
test.await();
}
}
//运行主类
class Run {
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
ThreadA a = new ThreadA(test);
a.start();
Thread.sleep(3000);
test.signal();
}
}
运行结果如下:
如图,成功的实现了等待/通知模式
Object类中的wait()方法相当于Condition类中await()方法。
Object类中的wait(long time)方法相当于Condition类中await(long time,TimeUnit unit)方法。
Object类中的notify()方法相当于Condition类中signal()方法。
Object类中的notifyAll()方法相当于Condition类中signalAll()方法。
修改上面代码,测试实现部分通知:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test {
private Lock lock = new ReentrantLock();
public Condition conditionB = lock.newCondition();
public Condition conditionA = lock.newCondition();
//等待
public void awaitA() {
try {
lock.lock(); //调用lock.lock()方法的线程就持有了"对象监视器",其他线程只有等待锁被释放时再次争抢
System.out.println("awaitA()时间为:" + System.currentTimeMillis());
conditionA.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//等待
public void awaitB() {
try {
lock.lock(); //调用lock.lock()方法的线程就持有了"对象监视器",其他线程只有等待锁被释放时再次争抢
System.out.println("awaitB()时间为:" + System.currentTimeMillis());
conditionB.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//通知
public void signalA() {
try {
lock.lock();
System.out.println("signalA()时间为:" + System.currentTimeMillis());
conditionA.signalAll();
} finally {
lock.unlock();
}
}
//通知
public void signalB() {
try {
lock.lock();
System.out.println("signalB()时间为:" + System.currentTimeMillis());
conditionB.signalAll();
} finally {
lock.unlock();
}
}
}
//线程类
class ThreadA extends Thread {
private Test test;
public ThreadA(Test test) {
super();
this.test = test;
}
@Override
public void run() {
test.awaitA();
}
}
//线程类
class ThreadB extends Thread {
private Test test;
public ThreadB(Test test) {
super();
this.test = test;
}
@Override
public void run() {
test.awaitB();
}
}
//运行主类
class Run {
public static void main(String[] args) throws InterruptedException {
Test test = new Test();
ThreadA a = new ThreadA(test);
a.start();
ThreadB b = new ThreadB(test);
b.start();
Thread.sleep(3000);
test.signalA(); //唤醒A
}
}
实验结果:
由图可以看出,只有A被唤醒了。所以实现了部分唤醒的功能。
通过此实验可以得知,使用ReentrantLock对象可以唤醒指定种类的线程,这是控制部分线程行为的方便方式。