1,两种方式简单介绍:
1.1 使用Synchronized关键字
Synchronized + wait() + notifyAll()
注意点:
判断条件用while循环,如果用if会出现虚假唤醒。
1.2使用Lock接口
ReentrantLock + Condition + await() + singsignalAll()
注意点:
Lock lock = new ReentrantLock(); //注意Lock 的实现类
Condition condition = lock.newCondition(); //注意Condition通过lock获取
2,使用synchronized
直接上代码:
/**
* 资源类
* @author dangkaimin
*/
public class Source {
private int number = 0; //资源
/* 生产 */
public synchronized void push() {
while(number == 1){ //判断 注意判断条件用while,如果用if会出现虚假唤醒
this.wait(); //等待
}
number = 1; //业务
System.out.println(Thread.currentThread().getName() + "push number = " + number);
this.notifyAll(); //通知
}
/* 消费 */
public synchronized void pop() {
while(number == 0){ //判断
this.wait(); //等待
}
number = 0; //业务
System.out.println(Thread.currentThread().getName() + "pop number = " + number);
this.notifyAll(); //通知
}
public static void main(String[] args){
Source source = new Source();
/* 生产者*/
new Thread( () -> {
while(true) {
source.push();
}
}).start();
/* 消费者*/
new Thread( () -> {
while(true) {
source.pop();
}
}).start();
}
3,使用Lock接口
/**
* 资源类
* @author dangkaimin
*/
public class Source {
private int number = 0; //资源
private Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
/* 生产 */
public void push() {
lock.lock();
try {
while(number == 1){ //判断
condition.await(); //等待
}
number = 1; //业务
System.out.println(Thread.currentThread().getName() + " push number = " + number);
condition.signalAll(); //通知
}finally {
lock.unlock();
}
}
/* 消费 */
public void pop() {
lock.lock();
try {
while(number == 0){ //判断
condition.await(); //等待
}
number = 0; //业务
System.out.println(Thread.currentThread().getName() + " pop number = " + number);
condition.signalAll(); //通知
} finally {
lock.unlock();
}
}
public static void main(String[] args){
Source source = new Source();
/* 生产者*/
new Thread( () -> {
while(true) {
source.push();
}
},"A").start();
/* 消费者*/
new Thread( () -> {
while(true) {
source.pop();
}
},"B").start();
}
}
3,Lock升级版:通过condition实现线程的精准通知。
流程:A唤醒B,B唤醒C,C唤醒A
注意点:
- 使用一个锁的不同condition
- 注意判断条件的合理。
/**
* 资源类
* @author dangkaimin
*/
public class Source {
private int number = 1; //资源
private Lock lock = new ReentrantLock();
Condition condition_A = lock.newCondition();
Condition condition_B = lock.newCondition();
Condition condition_C = lock.newCondition();
public void method_A() {
lock.lock();
try {
while(number != 1){ //判断
condition_A.await(); //等待
}
number = 2;
System.out.println(Thread.currentThread().getName() + " A number = " + number);
condition_B.signal(); //唤醒A
}catch(Exception e){
}finally {
lock.unlock();
}
}
/* 消费 */
public void method_B() {
lock.lock();
try {
while(number != 2){ //判断
condition_B.await(); //等待
}
number = 3;
System.out.println(Thread.currentThread().getName() + " B number = " + number);
condition_C.signal(); //唤醒B
}catch(Exception e){
} finally {
lock.unlock();
}
}
public void method_C() {
lock.lock();
try {
while(number != 3){ //判断
condition_C.await(); //等待
}
number = 1;
System.out.println(Thread.currentThread().getName() + " C number = " + number);
condition_A.signal(); //唤醒A
}catch(Exception e){
} finally {
lock.unlock();
}
}
public static void main(String[] args){
Source source = new Source();
new Thread( () -> {
while(true) {
source.method_A();
}
},"method_A").start();
new Thread( () -> {
while(true) {
source.method_B();
}
},"method_B").start();
new Thread( () -> {
while(true) {
source.method_C();
}
},"method_C").start();
}
}
精准通知结果如下:
method_C C number = 1
method_A A number = 2
method_B B number = 3
method_C C number = 1
method_A A number = 2
method_B B number = 3
method_C C number = 1
method_A A number = 2
method_B B number = 3
...