这里主要是在场景下帮助理解ReentrantLock和线程池的使用。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class GrabCourseTask implements Runnable {
private final String studentName;
private static int availableSeats = 10; // 假设有10个名额
private static final Lock lock = new ReentrantLock(); // 创建一个ReentrantLock实例
public GrabCourseTask(String studentName) {
this.studentName = studentName;
}
@Override
public void run() {
try {
if(grabCourse()) {
System.out.println(studentName + " 抢到了一个名额!");
} else {
System.out.println(studentName + " 没有抢到名额。");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println(studentName + " 在尝试抢课时被中断。");
}
}
private boolean grabCourse() throws InterruptedException {
// 尝试获取锁
if(lock.tryLock()) {
try {
if (availableSeats > 0) {
availableSeats--; // 减少一个名额
// 模拟服务器处理抢课请求需要一定的时间
Thread.sleep(100);
return true;
}
return false;
} finally {
lock.unlock(); // 确保在操作完成后释放锁
}
} else {
// 如果无法立即获取锁,则表示当前有其他线程正在操作名额,直接返回失败
return false;
}
}
}
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class CourseGrabbingSimulation {
public static void main(String[] args) {
// 创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
1, // 空闲线程存活时间
TimeUnit.SECONDS, // 时间单位
new ArrayBlockingQueue<>(5)); // 任务队列
// 模拟多个学生抢课
for (int i = 1; i <= 15; i++) {
String studentName = "学生" + i;
executor.execute(new GrabCourseTask(studentName));
}
// 关闭线程池
executor.shutdown();
}
}
在真实的抢课系统中,抢课的逻辑会更加复杂,需要考虑数据库的并发访问、事务处理、网络延迟等因素。
为了简化示例,这里使用了 ReentrantLock来控制对 availableSeats 的访问,保证了线程安全。在实际应用中,可能需要更复杂的并发控制机制。