likes
comments
collection
share

深耕 JDK 源码 - Semaphore

作者站长头像
站长
· 阅读数 4

在 Java 并发编程中,Semaphore(信号量)是一种用于控制资源访问和线程协作的多线程工具。它允许多个线程同时访问某个共享资源,但限制同时访问的线程数量,从而实现对并发访问的控制。Semaphore 是 Java 并发包(java.util.concurrent)中提供的一个类,从 JDK5 开始引入,并在 JDK8 中进行了一些改进。

Semaphore 的实现原理

Semaphore 的实现原理基于计数器和同步器的概念。Semaphore 内部维护一个计数器,该计数器表示当前可用的许可数量。线程可以通过调用 Semaphore 的 acquire() 方法来请求获取许可,如果当前许可数量大于0,则线程会获取到许可并将许可数量减一;否则,线程将被阻塞直到有可用许可。当线程完成访问共享资源后,需要通过调用 Semaphore 的 release() 方法来释放许可,从而增加许可数量,供其他线程继续获取。

Semaphore 还支持公平性和非公平性两种模式,默认是非公平模式。在公平模式下,线程会按照请求的顺序获取许可,而在非公平模式下,线程可能会通过竞争直接获取许可,从而导致某些线程获取到更多的许可。

Semaphore 的常见用法

Semaphore 在多线程编程中有很多常见的用法,包括但不限于以下几种:

1.限制并发访问数量:

Semaphore 可以用来限制同时访问某个共享资源的线程数量。通过设置 Semaphore 的许可数量,可以控制允许同时访问资源的线程数量,从而避免资源的过度竞争和争夺。例如,一个数据库连接池可以使用 Semaphore 来限制同时访问数据库的连接数量,从而避免数据库连接过多导致性能下降。

import java.util.concurrent.Semaphore;

public class ConnectionPool {
    private final Semaphore semaphore;
    // 初始化连接池
    public ConnectionPool(int poolSize) {
        semaphore = new Semaphore(poolSize);
        // 初始化连接
    }

    // 获取数据库连接
    public Connection getConnection() throws InterruptedException {
        semaphore.acquire();
        // 获取连接
    }

    // 释放数据库连接
    public void releaseConnection(Connection connection) {
        // 释放连接
        semaphore.release();
    }
}

2.控制线程的执行顺序

Semaphore 可以用来控制线程的执行顺序,通过设置 Semaphore 的许可数量为1,可以实现一种互斥的机制,即同一时刻只允许一个线程执行特定的代码段,从而实现对线程的顺序控制。例如,多个线程需要按照特定的顺序执行某些操作,可以使用 Semaphore 来实现。

import java.util.concurrent.Semaphore;

public class ThreadExecutionOrder {
    private final Semaphore semaphore = new Semaphore(1);
    private int currentThread = 1;

    public void thread1() throws InterruptedException {
        while (true) {
            semaphore.acquire();
            if (currentThread == 1) {
                System.out.println("Thread 1");
                currentThread = 2;
                semaphore.release();
                break;
            }
            semaphore.release();
        }
    }

    public void thread2() throws InterruptedException {
        while (true) {
            semaphore.acquire();
            if (currentThread == 2) {
                System.out.println("Thread 2");
                currentThread = 3;
                semaphore.release();
                break;
            }
            semaphore.release();
        }
    }

    public void thread3() throws InterruptedException {
        while (true) {
            semaphore.acquire();
            if (currentThread == 3) {
                System.out.println("Thread 3");
                currentThread = 1;
                semaphore.release();
                break;
            }
            semaphore.release();
        }
    }
}

3.实现线程间的协作

Semaphore 可以用来实现线程间的协作,通过设置 Semaphore 的初始许可数量和后续的许可获取和释放操作,可以实现线程的等待和唤醒操作,从而实现线程间的同步和协作。

import java.util.concurrent.Semaphore;

public class ThreadCooperation {
    private final Semaphore semaphore = new Semaphore(0);
    private boolean flag = false;

    public void printNumbers() throws InterruptedException {
        while (!flag) {
            semaphore.acquire();
            System.out.println("Printing numbers...");
            // 执行打印数字的操作
            semaphore.release();
            Thread.sleep(1000);
        }
    }

    public void signalPrintingComplete() {
        // 执行打印完成的操作
        flag = true;
        semaphore.release();
    }
}

4.控制资源的使用权限

Semaphore 还可以用来控制资源的使用权限,例如,限制同时访问某个资源的线程数量,或者限制某个资源的使用时间。通过合理设置 Semaphore 的许可数量和许可获取和释放操作,可以实现对资源的权限控制。

import java.util.concurrent.Semaphore;

public class ResourceAccessControl {
    private final Semaphore semaphore = new Semaphore(1);

    public void accessResource() throws InterruptedException {
        semaphore.acquire();
        // 访问资源
        Thread.sleep(1000);
        semaphore.release();
    }
}

这只是 Semaphore 的一些常见用法,实际上,Semaphore 还有很多其他的应用场景,可以根据实际需求进行灵活使用。

总结:

JDK8 中的 Semaphore 是一种用于控制资源访问和线程协作的多线程工具,其实现原理基于计数器和同步器的概念。Semaphore 可以用于限制并发访问数量、控制线程的执行顺序、实现线程间的协作以及控制资源的使用权限。通过合理设置 Semaphore 的许可数量和许可获取/释放操作,可以实现对多线程程序的高效管理和控制。

Semaphore 的使用方式相对简单,但需要注意以下几点:

1、在使用 Semaphore 时,应合理设置初始许可数量,确保许可的获取和释放操作能够满足实际需求,避免死锁或资源饥饿的情况。 2、在使用 Semaphore 进行线程协作时,需要谨慎处理信号量的获取和释放操作,避免出现竞态条件或错误的信号传递。 3、Semaphore 是可重入的,允许同一个线程多次获取许可,但需要注意合理管理许可的获取和释放,避免出现资源过度占用或过度释放的情况。 4、Semaphore 是基于计数器的概念,因此需要确保在每次许可获取后都能正确释放许可,避免许可泄漏导致资源无法再次被访问。

在多线程编程中,Semaphore 是一种强大的工具,能够在复杂的并发场景中提供灵活的资源管理和线程协作能力。合理使用 Semaphore 可以帮助开发者避免多线程并发问题,并提高多线程程序的性能和可靠性。