Lock的await()/signal()/signalAll() 阻塞等待与唤醒
通过Lock和Condition,实现一个生产者消费者的阻塞队列,看看这玩意到底是个啥
直接贴代码,转载自 https://blog.51cto.com/u_15287666/4904942
package com.example.demo.test;
import java.util.ArrayList;
import java.util.Arrays;
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;
public class MyBlockedQueue<T> {
// 使用Lock,生产者和消费者是竞争同一个锁,使用synchronized,生产者和消费者竞争的是同一个锁对象
final Lock lock = new ReentrantLock();
// 条件变量:队列不满
final Condition notFull = lock.newCondition();
// 条件变量:队列不空
final Condition notEmpty = lock.newCondition();
//队列
private volatile LinkedList<T> list = new LinkedList<>();
//队列长度
private final Integer LENGTH = 10;
// 生产者
void enq(T x) {
lock.lock();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
while (list.size() == LENGTH) {
System.out.println("队列满了....");
try {
// 等待队列不满
notFull.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("生产者加入数据:"+x);
// 省略入队操作
list.add(x);
// 入队后, 通知可出队
notEmpty.signal();
} finally {
lock.unlock();
}
}
// 消费者
void deq() {
lock.lock();
try {
while (list.isEmpty()) {
System.out.println("队列空了....");
// 等待队列不空
try {
notEmpty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
T v = list.poll();
System.out.println("消费者消费数据:"+v);
// 出队后,通知可入队
notFull.signal();
} finally {
lock.unlock();
}
}
public List<T> getList() {
return list;
}
public static void main(String[] args) throws InterruptedException {
MyBlockedQueue<Integer> myBlockedQueue = new MyBlockedQueue<>();
//生产者线程
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 20; i++) {
myBlockedQueue.enq(i);
}
}
});
//消费者线程
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
myBlockedQueue.deq();
}
}
});
thread1.start();
thread2.start();
try {
Thread.sleep(10500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("队列中还剩下没有消费的数据:"+Arrays.toString(myBlockedQueue.getList().toArray()));
}
}
mian方法,直接运行一下,看控制台输出
D:\JDK\JDK_1.8_201_64\bin\java.exe "-javaagent:D:\IDEA\idea\IntelliJ IDEA 2020.1.1\lib\idea_rt.jar=65134:D:\IDEA\idea\IntelliJ IDEA 2020.1.1\bin" -Dfile.encoding=UTF-8 -classpath D:\JDK\JDK_1.8_201_64\jre\lib\charsets.jar;D:\JDK\JDK_1.8_201_64\jre\lib\deploy.jar;D:\JDK\JDK_1.8_201_64\jre\lib\ext\access-bridge-64.jar;D:\JDK\JDK_1.8_201_64\jre\lib\ext\cldrdata.jar;D:\JDK\JDK_1.8_201_64\jre\lib\ext\dnsns.jar;D:\JDK\JDK_1.8_201_64\jre\lib\ext\jaccess.jar;D:\JDK\JDK_1.8_201_64\jre\lib\ext\jfxrt.jar;D:\JDK\JDK_1.8_201_64\jre\lib\ext\localedata.jar;D:\JDK\JDK_1.8_201_64\jre\lib\ext\nashorn.jar;D:\JDK\JDK_1.8_201_64\jre\lib\ext\sunec.jar;D:\JDK\JDK_1.8_201_64\jre\lib\ext\sunjce_provider.jar;D:\JDK\JDK_1.8_201_64\jre\lib\ext\sunmscapi.jar;D:\JDK\JDK_1.8_201_64\jre\lib\ext\sunpkcs11.jar;D:\JDK\JDK_1.8_201_64\jre\lib\ext\zipfs.jar;D:\JDK\JDK_1.8_201_64\jre\lib\javaws.jar;D:\JDK\JDK_1.8_201_64\jre\lib\jce.jar;D:\JDK\JDK_1.8_201_64\jre\lib\jfr.jar;D:\JDK\JDK_1.8_201_64\jre\lib\jfxswt.jar;D:\JDK\JDK_1.8_201_64\jre\lib\jsse.jar;D:\JDK\JDK_1.8_201_64\jre\lib\management-agent.jar;D:\JDK\JDK_1.8_201_64\jre\lib\plugin.jar;D:\JDK\JDK_1.8_201_64\jre\lib\resources.jar;D:\JDK\JDK_1.8_201_64\jre\lib\rt.jar;E:\山大考试\demoTTT\target\classes;C:\Users\windows\.m2\repository\org\springframework\boot\spring-boot-starter-web\2.3.7.RELEASE\spring-boot-starter-web-2.3.7.RELEASE.jar;C:\Users\windows\.m2\repository\org\springframework\boot\spring-boot-starter\2.3.7.RELEASE\spring-boot-starter-2.3.7.RELEASE.jar;C:\Users\windows\.m2\repository\org\springframework\boot\spring-boot\2.3.7.RELEASE\spring-boot-2.3.7.RELEASE.jar;C:\Users\windows\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.3.7.RELEASE\spring-boot-autoconfigure-2.3.7.RELEASE.jar;C:\Users\windows\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.3.7.RELEASE\spring-boot-starter-logging-2.3.7.RELEASE.jar;C:\Users\windows\.m2\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;C:\Users\windows\.m2\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;C:\Users\windows\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.13.3\log4j-to-slf4j-2.13.3.jar;C:\Users\windows\.m2\repository\org\apache\logging\log4j\log4j-api\2.13.3\log4j-api-2.13.3.jar;C:\Users\windows\.m2\repository\org\slf4j\jul-to-slf4j\1.7.30\jul-to-slf4j-1.7.30.jar;C:\Users\windows\.m2\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;C:\Users\windows\.m2\repository\org\yaml\snakeyaml\1.26\snakeyaml-1.26.jar;C:\Users\windows\.m2\repository\org\springframework\boot\spring-boot-starter-json\2.3.7.RELEASE\spring-boot-starter-json-2.3.7.RELEASE.jar;C:\Users\windows\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.11.3\jackson-databind-2.11.3.jar;C:\Users\windows\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.11.3\jackson-annotations-2.11.3.jar;C:\Users\windows\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.11.3\jackson-core-2.11.3.jar;C:\Users\windows\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.11.3\jackson-datatype-jdk8-2.11.3.jar;C:\Users\windows\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.11.3\jackson-datatype-jsr310-2.11.3.jar;C:\Users\windows\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.11.3\jackson-module-parameter-names-2.11.3.jar;C:\Users\windows\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\2.3.7.RELEASE\spring-boot-starter-tomcat-2.3.7.RELEASE.jar;C:\Users\windows\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.37\tomcat-embed-core-9.0.37.jar;C:\Users\windows\.m2\repository\org\glassfish\jakarta.el\3.0.3\jakarta.el-3.0.3.jar;C:\Users\windows\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.37\tomcat-embed-websocket-9.0.37.jar;C:\Users\windows\.m2\repository\org\springframework\spring-web\5.2.12.RELEASE\spring-web-5.2.12.RELEASE.jar;C:\Users\windows\.m2\repository\org\springframework\spring-beans\5.2.12.RELEASE\spring-beans-5.2.12.RELEASE.jar;C:\Users\windows\.m2\repository\org\springframework\spring-webmvc\5.2.12.RELEASE\spring-webmvc-5.2.12.RELEASE.jar;C:\Users\windows\.m2\repository\org\springframework\spring-aop\5.2.12.RELEASE\spring-aop-5.2.12.RELEASE.jar;C:\Users\windows\.m2\repository\org\springframework\spring-context\5.2.12.RELEASE\spring-context-5.2.12.RELEASE.jar;C:\Users\windows\.m2\repository\org\springframework\spring-expression\5.2.12.RELEASE\spring-expression-5.2.12.RELEASE.jar;C:\Users\windows\.m2\repository\org\mybatis\spring\boot\mybatis-spring-boot-starter\2.1.1\mybatis-spring-boot-starter-2.1.1.jar;C:\Users\windows\.m2\repository\org\springframework\boot\spring-boot-starter-jdbc\2.3.7.RELEASE\spring-boot-starter-jdbc-2.3.7.RELEASE.jar;C:\Users\windows\.m2\repository\com\zaxxer\HikariCP\3.4.5\HikariCP-3.4.5.jar;C:\Users\windows\.m2\repository\org\springframework\spring-jdbc\5.2.12.RELEASE\spring-jdbc-5.2.12.RELEASE.jar;C:\Users\windows\.m2\repository\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\2.1.1\mybatis-spring-boot-autoconfigure-2.1.1.jar;C:\Users\windows\.m2\repository\org\mybatis\mybatis\3.5.3\mybatis-3.5.3.jar;C:\Users\windows\.m2\repository\org\mybatis\mybatis-spring\2.0.3\mybatis-spring-2.0.3.jar;C:\Users\windows\.m2\repository\mysql\mysql-connector-java\8.0.11\mysql-connector-java-8.0.11.jar;C:\Users\windows\.m2\repository\org\projectlombok\lombok\1.18.12\lombok-1.18.12.jar;C:\Users\windows\.m2\repository\commons-lang\commons-lang\2.6\commons-lang-2.6.jar;C:\Users\windows\.m2\repository\com\alibaba\fastjson\1.2.49\fastjson-1.2.49.jar;C:\Users\windows\.m2\repository\com\squareup\okhttp3\okhttp\3.6.0\okhttp-3.6.0.jar;C:\Users\windows\.m2\repository\com\squareup\okio\okio\1.11.0\okio-1.11.0.jar;C:\Users\windows\.m2\repository\org\springframework\boot\spring-boot-starter-amqp\2.5.5\spring-boot-starter-amqp-2.5.5.jar;C:\Users\windows\.m2\repository\org\springframework\spring-messaging\5.2.12.RELEASE\spring-messaging-5.2.12.RELEASE.jar;C:\Users\windows\.m2\repository\org\springframework\amqp\spring-rabbit\2.2.9.RELEASE\spring-rabbit-2.2.9.RELEASE.jar;C:\Users\windows\.m2\repository\com\rabbitmq\amqp-client\5.9.0\amqp-client-5.9.0.jar;C:\Users\windows\.m2\repository\org\springframework\amqp\spring-amqp\2.2.9.RELEASE\spring-amqp-2.2.9.RELEASE.jar;C:\Users\windows\.m2\repository\org\springframework\retry\spring-retry\1.2.5.RELEASE\spring-retry-1.2.5.RELEASE.jar;C:\Users\windows\.m2\repository\org\springframework\spring-tx\5.2.12.RELEASE\spring-tx-5.2.12.RELEASE.jar;C:\Users\windows\.m2\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;C:\Users\windows\.m2\repository\org\springframework\spring-core\5.2.12.RELEASE\spring-core-5.2.12.RELEASE.jar;C:\Users\windows\.m2\repository\org\springframework\spring-jcl\5.2.12.RELEASE\spring-jcl-5.2.12.RELEASE.jar com.example.demo.test.MyBlockedQueue
生产者加入数据:1
生产者加入数据:2
生产者加入数据:3
生产者加入数据:4
生产者加入数据:5
生产者加入数据:6
生产者加入数据:7
生产者加入数据:8
生产者加入数据:9
生产者加入数据:10
队列满了....
消费者消费数据:1
消费者消费数据:2
生产者加入数据:11
生产者加入数据:12
队列满了....
消费者消费数据:3
消费者消费数据:4
消费者消费数据:5
消费者消费数据:6
消费者消费数据:7
消费者消费数据:8
消费者消费数据:9
消费者消费数据:10
生产者加入数据:13
生产者加入数据:14
生产者加入数据:15
生产者加入数据:16
生产者加入数据:17
生产者加入数据:18
生产者加入数据:19
生产者加入数据:20
队列中还剩下没有消费的数据:[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
Process finished with exit code 0
大体说一下
创建2个线程,一个生产者线程,一个消费者线程
生产者线程,如果队列满了,就notFull.await(),阻塞等待,让出锁,如果不满,就加入队列数据,同时唤醒消费者那边的阻塞等待
消费者线程,如果队列为空,咱就notEmpty.await(),阻塞等待,让出锁,如果不为空,就消费