關(guān)鍵字synchronized與wait()/notify()這兩個方法一起使用可以實(shí)現(xiàn)等待/通知模式, Lock鎖的newContition()方法返回Condition對象,Condition類也可以實(shí)現(xiàn)等待/通知模式。
用notify()通知時,JVM會隨機(jī)喚醒某個等待的線程, 使用Condition類可以進(jìn)行選擇性通知, Condition比較常用的兩個方法:
● await()會使當(dāng)前線程等待,同時會釋放鎖,當(dāng)其他線程調(diào)用signal()時,線程會重新獲得鎖并繼續(xù)執(zhí)行。
● signal()用于喚醒一個等待的線程。
注意:在調(diào)用Condition的await()/signal()方法前,也需要線程持有相關(guān)的Lock鎖,調(diào)用await()后線程會釋放這個鎖,在singal()調(diào)用后會從當(dāng)前Condition對象的等待隊(duì)列中,喚醒 一個線程,喚醒的線程嘗試獲得鎖, 一旦獲得鎖成功就繼續(xù)執(zhí)行。
package com.wkcto.lock.condition;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Condition等待與通知
*/
public class Test01 {
//定義鎖
static Lock lock = new ReentrantLock();
//獲得Condtion對象
static Condition condition = lock.newCondition();
//定義線程子類
static class SubThread extends Thread{
@Override
public void run() {
try {
lock.lock(); //在調(diào)用await()前必須先獲得鎖
System.out.println("method lock");
condition.await(); //等待
System.out.println("method await");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); //釋放鎖
System.out.println("method unlock");
}
}
}
public static void main(String[] args) throws InterruptedException {
SubThread t = new SubThread();
t.start();
//子線程啟動后,會轉(zhuǎn)入等待狀態(tài)
Thread.sleep(3000);
//主線程在睡眠3秒后,喚醒子線程的等待
try {
lock.lock();
condition.signal();
} finally {
lock.unlock();
}
}
}
package com.wkcto.lock.condition;
import java.io.PipedOutputStream;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* 多個Condition實(shí)現(xiàn)通知部分線程, 使用更靈活
*/
public class Test02 {
static class Service{
private ReentrantLock lock = new ReentrantLock(); //定義鎖對象
//定義兩個Condtion對象
private Condition conditionA = lock.newCondition();
private Condition conditionB = lock.newCondition();
//定義方法,使用conditionA等待
public void waitMethodA(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " begin wait:" + System.currentTimeMillis());
conditionA.await(); //等待
System.out.println(Thread.currentThread().getName() + " end wait:" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//定義方法,使用conditionB等待
public void waitMethodB(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " begin wait:" + System.currentTimeMillis());
conditionB.await(); //等待
System.out.println(Thread.currentThread().getName() + " end wait:" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//定義方法喚醒conditionA對象上的等待
public void signalA(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " sigal A time = " + System.currentTimeMillis());
conditionA.signal();
System.out.println(Thread.currentThread().getName() + " sigal A time = " + System.currentTimeMillis());
} finally {
lock.unlock();
}
}
//定義方法喚醒conditionB對象上的等待
public void signalB(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + " sigal A time = " + System.currentTimeMillis());
conditionB.signal();
System.out.println(Thread.currentThread().getName() + " sigal A time = " + System.currentTimeMillis());
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
Service service = new Service();
//開啟兩個線程,分別調(diào)用waitMethodA(),waitMethodB()方法
new Thread(new Runnable() {
@Override
public void run() {
service.waitMethodA();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
service.waitMethodB();
}
}).start();
Thread.sleep(3000); //main線程睡眠3秒
// service.signalA(); //喚醒 conditionA對象上的等待,conditionB上的等待依然繼續(xù)等待
service.signalB();
}
}
package com.wkcto.lock.condition;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 使用Condition實(shí)現(xiàn)生產(chǎn)者/消費(fèi)者設(shè)計(jì)模式, 兩個 線程交替打印
*/
public class Test03 {
static class MyService{
private Lock lock = new ReentrantLock(); //創(chuàng)建鎖對象
private Condition condition = lock.newCondition(); //創(chuàng)建Condition對象
private boolean flag = true; //定義交替打印標(biāo)志
//定義方法只打印----橫線
public void printOne(){
try {
lock.lock(); //鎖定
while (flag){ //當(dāng)flag為true等待
System.out.println(Thread.currentThread().getName() + " waiting...");
condition.await();
}
//flag為false時打印
System.out.println(Thread.currentThread().getName() + " ---------------- ");
flag = true; //修改交替打印標(biāo)志
condition.signal(); //通知另外的線程打印
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); //釋放鎖對象
}
}
//定義方法只打印***橫線
public void printTwo(){
try {
lock.lock(); //鎖定
while (!flag){ //當(dāng)flag為false等待
System.out.println(Thread.currentThread().getName() + " waiting...");
condition.await();
}
//flag為true時打印
System.out.println(Thread.currentThread().getName() + " ****** ");
flag = false; //修改交替打印標(biāo)志
condition.signal(); //通知另外的線程打印
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); //釋放鎖對象
}
}
}
public static void main(String[] args) {
MyService myService = new MyService();
//創(chuàng)建線程打印--
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
myService.printOne();
}
}
}).start();
//創(chuàng)建線程打印**
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
myService.printTwo();
}
}
}).start();
}
}