请编写一个示例程序展示如何使用 Semaphore 类控制对共享资源的并发访问数量。

示例程序:使用 Semaphore 控制对共享资源的并发访问数量

以下程序模拟了多个线程对一个共享资源(例如数据库连接)的访问,同时通过 Semaphore 限制并发访问数量为 3。


import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    // 创建一个信号量,限制最多允许 3 个线程访问共享资源
    private static final Semaphore semaphore = new Semaphore(3);

    public static void main(String[] args) {
        // 创建多个线程模拟并发访问
        for (int i = 1; i <= 10; i++) {
            new Thread(new Task(i)).start();
        }
    }

    // 模拟任务类,每个线程访问共享资源
    static class Task implements Runnable {
        private final int threadId;

        public Task(int threadId) {
            this.threadId = threadId;
        }

        @Override
        public void run() {
            try {
                System.out.println("Thread " + threadId + " is waiting for access.");
                // 获取许可
                semaphore.acquire();
                System.out.println("Thread " + threadId + " has acquired access.");

                // 模拟访问共享资源
                Thread.sleep((long) (Math.random() * 5000)); // 模拟耗时操作

                System.out.println("Thread " + threadId + " is releasing access.");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                // 释放许可
                semaphore.release();
            }
        }
    }
}

输出示例

程序输出可能如下(具体顺序可能因线程调度而异):

Thread 1 is waiting for access.
Thread 2 is waiting for access.
Thread 3 is waiting for access.
Thread 4 is waiting for access.
Thread 5 is waiting for access.
Thread 1 has acquired access.
Thread 2 has acquired access.
Thread 3 has acquired access.
Thread 1 is releasing access.
Thread 4 has acquired access.
Thread 3 is releasing access.
Thread 5 has acquired access.
Thread 2 is releasing access.
Thread 6 is waiting for access.
Thread 6 has acquired access.
Thread 4 is releasing access.
...

程序说明

  1. Semaphore 创建
    • Semaphore semaphore = new Semaphore(3);:限制最多 3 个线程同时访问共享资源。
  2. acquire() 方法
    • 当一个线程调用 acquire() 时,如果信号量许可(permits)数量大于 0,则获取许可并进入临界区。
    • 如果信号量许可为 0,线程会阻塞,直到有线程释放许可。
  3. release() 方法
    • 调用 release() 后,释放一个许可,并唤醒一个等待线程(如果有)。
  4. 模拟共享资源访问
    • 在临界区中,线程调用 Thread.sleep() 模拟访问耗时。
  5. 线程调度
    • 由于线程调度的随机性,不同线程的访问顺序可能不同,但始终确保同时最多有 3 个线程访问共享资源。

应用场景

  1. 数据库连接池
    • 限制同时访问数据库的线程数量,避免超出数据库连接的限制。
  2. 限流控制
    • 在高并发系统中,限制访问某些服务或资源的线程数量,防止系统过载。
  3. 多线程下载
    • 限制同时进行的文件下载任务数量。

发表评论

后才能评论