ZetCode

Java Semaphore

最后修改:2025 年 2 月 15 日

在本文中,我们将展示如何使用 Semaphore 同步 Java 线程。

Semaphore 是一种同步工具,它通过一组许可来控制对共享资源的访问。它对于管理有限的资源非常有用,例如数据库连接或线程池,在这些情况下,只有一定数量的线程可以同时访问该资源。

Semaphore 使用一定数量的许可进行初始化。 线程可以使用 acquire 方法获取许可,并使用 release 方法释放许可。 如果没有可用的许可,线程将阻塞,直到另一个线程释放许可为止。

Semaphore 示例

以下示例演示如何使用 Semaphore 来控制对共享资源的访问。

Main.java
import java.util.concurrent.Semaphore;

class SharedResource {
    private final Semaphore semaphore;

    public SharedResource(int permits) {
        this.semaphore = new Semaphore(permits);
    }

    public void useResource() {
        try {
            semaphore.acquire(); // Acquire a permit
            System.out.println(Thread.currentThread().getName() + " is using the resource");
            Thread.sleep(2000); // Simulate resource usage
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            System.out.println(Thread.currentThread().getName() + " is releasing the resource");
            semaphore.release(); // Release the permit
        }
    }
}

class Worker implements Runnable {
    private final SharedResource sharedResource;

    public Worker(SharedResource sharedResource) {
        this.sharedResource = sharedResource;
    }

    @Override
    public void run() {
        sharedResource.useResource();
    }
}

void main() throws InterruptedException {
    SharedResource sharedResource = new SharedResource(2); // Allow 2 permits

    Thread t1 = new Thread(new Worker(sharedResource), "Thread-1");
    Thread t2 = new Thread(new Worker(sharedResource), "Thread-2");
    Thread t3 = new Thread(new Worker(sharedResource), "Thread-3");
    Thread t4 = new Thread(new Worker(sharedResource), "Thread-4");

    t1.start();
    t2.start();
    t3.start();
    t4.start();

    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

在此程序中,使用 Semaphore 限制对共享资源的访问。 一次只能有两个线程可以访问该资源,因为信号量使用两个许可进行初始化。

private final Semaphore semaphore;

public SharedResource(int permits) {
    this.semaphore = new Semaphore(permits);
}

SharedResource 类使用具有指定数量许可的 Semaphore 初始化。

semaphore.acquire(); // Acquire a permit

线程在访问资源之前获取许可。 如果没有可用的许可,线程将阻塞。

semaphore.release(); // Release the permit

使用资源后,线程释放许可,允许其他线程获取它。

SharedResource sharedResource = new SharedResource(2); // Allow 2 permits

SharedResource 使用两个许可进行初始化,这意味着一次只能有两个线程可以访问该资源。

$ java Main.java
Thread-1 is using the resource
Thread-2 is using the resource
Thread-1 is releasing the resource
Thread-2 is releasing the resource
Thread-3 is using the resource
Thread-4 is using the resource
Thread-3 is releasing the resource
Thread-4 is releasing the resource

具有公平性的 Semaphore

以下示例演示如何使用具有公平性的 Semaphore。 启用公平性后,线程将按照请求的顺序获取许可。

Main.java
import java.util.concurrent.Semaphore;

class SharedResource {
    private final Semaphore semaphore;

    public SharedResource(int permits, boolean fair) {
        this.semaphore = new Semaphore(permits, fair);
    }

    public void useResource() {
        try {
            semaphore.acquire(); // Acquire a permit
            System.out.println(Thread.currentThread().getName() + " is using the resource");
            Thread.sleep(2000); // Simulate resource usage
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            System.out.println(Thread.currentThread().getName() + " is releasing the resource");
            semaphore.release(); // Release the permit
        }
    }
}

class Worker implements Runnable {
    private final SharedResource sharedResource;

    public Worker(SharedResource sharedResource) {
        this.sharedResource = sharedResource;
    }

    @Override
    public void run() {
        sharedResource.useResource();
    }
}

void main() throws InterruptedException {
    SharedResource sharedResource = new SharedResource(2, true); // Allow 2 permits with fairness

    Thread t1 = new Thread(new Worker(sharedResource), "Thread-1");
    Thread t2 = new Thread(new Worker(sharedResource), "Thread-2");
    Thread t3 = new Thread(new Worker(sharedResource), "Thread-3");
    Thread t4 = new Thread(new Worker(sharedResource), "Thread-4");

    t1.start();
    t2.start();
    t3.start();
    t4.start();

    t1.join();
    t2.join();
    t3.join();
    t4.join();
}

在此程序中,Semaphore 启用公平性进行初始化。 这确保了线程按照它们请求的顺序获取许可。

public SharedResource(int permits, boolean fair) {
    this.semaphore = new Semaphore(permits, fair);
}

Semaphore 启用公平性进行初始化,确保线程按照它们请求的顺序获取许可。

$ java Main.java
Thread-1 is using the resource
Thread-2 is using the resource
Thread-1 is releasing the resource
Thread-2 is releasing the resource
Thread-3 is using the resource
Thread-4 is using the resource
Thread-3 is releasing the resource
Thread-4 is releasing the resource

带有 Semaphore 示例的线程池

以下示例演示如何使用 Semaphore 来实现线程池。 线程池将并发执行的任务数量限制为固定大小。

Main.java
import java.util.concurrent.Semaphore;

class Task implements Runnable {
    private final int taskId;
    private final Semaphore semaphore;

    public Task(int taskId, Semaphore semaphore) {
        this.taskId = taskId;
        this.semaphore = semaphore;
    }

    @Override
    public void run() {
        try {
            semaphore.acquire(); // Acquire a permit
            System.out.println("Task " + taskId + " is running on " + Thread.currentThread().getName());
            Thread.sleep(2000); // Simulate task execution
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            System.out.println("Task " + taskId + " is completed");
            semaphore.release(); // Release the permit
        }
    }
}

void main() throws InterruptedException {
    int poolSize = 3; // Maximum number of concurrent tasks
    Semaphore semaphore = new Semaphore(poolSize);

    // Create and start 10 tasks
    for (int i = 1; i <= 10; i++) {
        Thread thread = new Thread(new Task(i, semaphore));
        thread.start();
    }

    // Wait for all tasks to complete
    Thread.sleep(10000); // Adjust sleep time as needed
    System.out.println("All tasks completed");
}

在此程序中,使用 Semaphore 将并发执行的任务数量限制为固定大小(在本例中为 3)。 每个任务在执行之前获取许可,并在完成后释放它。

semaphore.acquire(); // Acquire a permit

任务在开始执行之前获取许可。 如果没有可用的许可,该任务将阻塞,直到释放许可为止。

semaphore.release(); // Release the permit

执行完成后,任务释放许可,允许另一个任务获取它。

int poolSize = 3; // Maximum number of concurrent tasks
Semaphore semaphore = new Semaphore(poolSize);

Semaphore 使用大小为 3 的池进行初始化,这意味着只有 3 个任务可以并发运行。

$ java Main.java
Task 1 is running on Thread-0
Task 2 is running on Thread-1
Task 3 is running on Thread-2
Task 1 is completed
Task 4 is running on Thread-3
Task 2 is completed
Task 5 is running on Thread-4
Task 3 is completed
Task 6 is running on Thread-5
Task 4 is completed
Task 7 is running on Thread-6
Task 5 is completed
Task 8 is running on Thread-7
Task 6 is completed
Task 9 is running on Thread-8
Task 7 is completed
Task 10 is running on Thread-9
Task 8 is completed
Task 9 is completed
Task 10 is completed
All tasks completed

来源

Java Semaphore - 参考

在本文中,我们展示了如何使用 Semaphore 同步 Java 线程以进行资源管理。

作者

我的名字是 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。 我从 2007 年开始撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有Java教程