使用ReentrantLock+Condition模拟PV操作,实现多线程竞争数据库连接池资源、资源耗尽后阻塞等待、归还资源后唤醒阻塞线程的场景(代码中为10个线程竞争5个数据库连接资源)
ConnectionPool.class(连接池)
package demo.lock.db;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import org.apache.commons.collections4.CollectionUtils;
public class ConnectionPool {
private static final int POOL_SIZE = 5;
public static List<Connection> connections;
public static volatile int signal = POOL_SIZE;
public static ReentrantLock lock = new ReentrantLock();
public static Condition condition = lock.newCondition();
public static void init() {
connections = new ArrayList<>(POOL_SIZE);
for (int i = 0; i < POOL_SIZE; i++) {
connections.add(new Connection("connection-" + i));
}
}
public static Connection getConnection() throws Exception {
lock.lock();
try {
if (signal <= 0) {
condition.await();
}
while (true) {
if (signal > 0) {
List<Connection> freeConnections = connections.stream()
.filter(x -> x.state.equals(ConnectionState.FREE)).collect(Collectors.toList());
Connection currConnection =
CollectionUtils.isEmpty(freeConnections) ? null : freeConnections.get(0);
if (null == currConnection) {
return null;
}
currConnection.state = ConnectionState.BUSY;
signal--;
System.out.println("当前线程:" + Thread.currentThread().getName() + " 抢到数据库连接:"
+ currConnection.getName() + " 当前连接池中空闲连接数:" + signal);
return currConnection;
}
}
} finally {
lock.unlock();
}
}
public static void repayConnection(Connection connection) {
if (null == connection) {
return;
}
lock.lock();
try {
connections.forEach(x -> x.state = connection.equals(x) ? ConnectionState.FREE : x.state);
signal++;
System.out.println("当前线程:" + Thread.currentThread().getName() + " 归还数据库连接:" + connection.getName()
+ " 当前连接池中空闲连接数:" + signal);
condition.signal();
} finally {
lock.unlock();
}
}
}
Connection.class(连接对象)
package demo.lock.db;
public class Connection {
String name;
ConnectionState state = ConnectionState.FREE;
public Connection(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "当前连接:" + ",状态:" + state.state;
}
}
ConnectionState.class(连接状态枚举)
package demo.lock.db;
public enum ConnectionState {
FREE(0, "空闲"), BUSY(1, "忙碌");
int code;
String state;
ConnectionState(int code, String state) {
this.code = code;
this.state = state;
}
}
Application.class(程序入口)
package demo.lock;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import demo.lock.db.Connection;
import demo.lock.db.ConnectionPool;
public class Application {
ThreadPoolExecutor executor =
new ThreadPoolExecutor(10, 10, 30, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>());
public void execute() {
for (int i = 0; i < 10; i++) {
executor.submit(new Runnable() {
@Override
public void run() {
try {
Connection connection = ConnectionPool.getConnection();
Thread.sleep((long)(Math.random() * 1000));
ConnectionPool.repayConnection(connection);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
public void shutdown() {
if (null == executor) {
return;
}
executor.shutdown();
}
public static void main(String[] args) throws InterruptedException {
ConnectionPool.init();
Application application = new Application();
application.execute();
Thread.sleep(10000L);
application.shutdown();
}
}
运行结果
![在这里插入图片描述](https://img-blog.csdnimg.cn/fc6877b4e9904df4ad2da9b11f4b7b11.png)