JAVA 多线程之信号量(Semaphore)实例详解
什么是信号量
信号量是操作系统中的一种同步工具,它可以用来控制同时访问某些资源的线程数量。Semaphore 是 Java 开发中一个用于控制线程的工具类,它可以用于控制同时执行的线程数量,可以看作是一种限流的方式。
Semaphore 所提供的计数器是被初始化的,并且该计数器有一个上限,它表示的是共享资源的个数。当某个线程需要访问共享资源时,它必须在这个 Semaphore 中占用一个许可(permit)。当许可被占用时,Semaphore 的计数器会减去 1,当计数器为 0 时,将不再允许执行占用许可的线程,其它的线程必须等待已下占用的线程释放许可。当占用许可的线程使用完共享资源后,它需要释放许可,这样 Semaphore 的计数器会加 1,表示又有一个许可可以被占用。
Semaphore 的使用
Semaphore 的常用方法主要有两个:acquire()
和 release()
。
acquire()
方法用于申请一个许可,如果当前 Semaphore 的计数器大于 0,就可以申请许可,计数器值减 1。如果当前 Semaphore 的计数器为 0,调用 acquire()
方法的线程将一直阻塞,直到有许可可用为止。
release()
方法用于释放一个许可,计数器增加 1。
在使用 Semaphore 时,需要注意的是:申请和释放许可的线程必须是同一个线程。
示例一
下面是一个简单的示例,演示 Semaphore 的使用:
import java.util.concurrent.Semaphore;
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(2); // 初始化信号量为 2
new MyThread(semaphore, "A").start();
new MyThread(semaphore, "B").start();
new MyThread(semaphore, "C").start();
new MyThread(semaphore, "D").start();
}
static class MyThread extends Thread {
private Semaphore semaphore;
public MyThread(Semaphore semaphore, String name) {
super(name);
this.semaphore = semaphore;
}
@Override
public void run() {
try {
semaphore.acquire(); // 获取许可
System.out.println(Thread.currentThread().getName() + " 获取许可...");
Thread.sleep(2000); // 模拟线程执行任务需要占用许可
semaphore.release(); // 释放许可
System.out.println(Thread.currentThread().getName() + " 释放许可...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
在上面的示例中,我们创建了一个 Semaphore 对象,并将其初始值设置为 2。然后我们创建了 4 个线程,并将 Semaphore 对象传递给这些线程。在线程中,我们先尝试获取许可,如果获取到许可,则打印获取许可的信息,并模拟线程执行任务需要占用许可的时间;随后调用 release()
方法释放许可,并打印释放许可的信息。
运行该程序,输出如下:
A 获取许可...
C 获取许可...
C 释放许可...
D 获取许可...
A 释放许可...
D 释放许可...
B 获取许可...
B 释放许可...
从输出可以看出,同一时刻只有两个线程可以获取到许可,并且每个线程获得许可之后都需要释放许可,才能让其它线程获取许可。
示例二
下面是另外一个示例,演示使用 Semaphore 模拟某个共享资源的访问:
import java.util.concurrent.Semaphore;
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3); // 初始化信号量为 3
new ShareResource(semaphore, "A").start();
new ShareResource(semaphore, "B").start();
new ShareResource(semaphore, "C").start();
}
static class ShareResource extends Thread {
private Semaphore semaphore;
public ShareResource(Semaphore semaphore, String name) {
super(name);
this.semaphore = semaphore;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 尝试访问共享资源...");
semaphore.acquire(); // 获取许可
System.out.println(Thread.currentThread().getName() + " 成功访问共享资源");
Thread.sleep(2000); // 模拟线程执行任务需要占用许可
semaphore.release(); // 释放许可
System.out.println(Thread.currentThread().getName() + " 释放了许可");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
在上面的示例中,我们创建了一个 Semaphore 对象,并将其初始值设置为 3。然后我们创建了 3 个线程,并将 Semaphore 对象传递给这些线程。在线程中,我们尝试获取许可,如果获取到许可,则打印成功访问共享资源的信息,并模拟线程执行任务需要占用许可的时间;随后调用 release()
方法释放许可,并打印释放许可的信息。
运行该程序,输出如下:
A 尝试访问共享资源...
A 成功访问共享资源
B 尝试访问共享资源...
B 成功访问共享资源
C 尝试访问共享资源...
C 成功访问共享资源
A 释放了许可
B 释放了许可
C 释放了许可
从输出可以看出,在同一时刻只有 3 个线程可以成功访问共享资源。每个线程访问共享资源之前都需要获取许可,访问结束后需要释放许可。如果没有许可可用,则线程会一直阻塞,直到有许可可用为止。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JAVA 多线程之信号量(Semaphore)实例详解 - Python技术站