Semaphore 是 Java.util.concurrent 包中提供的一个线程同步工具类,它可以用来控制同时访问某个资源的线程数量。
Semaphore 代码示例 1 :
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
public static void main(String[] args) {
// 创建一个 Semaphore 对象,初始值为 3
Semaphore semaphore = new Semaphore(3);
// 创建 5 个线程
for (int i = 1; i <= 5; i++) {
new Thread(() -> {
try {
// 尝试获取许可
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " 获取到许可");
// 模拟线程执行一段时间
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " 执行完毕");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放许可
semaphore.release();
System.out.println(Thread.currentThread().getName() + " 释放许可");
}
}).start();
}
}
}
代码解析:
- 创建一个
Semaphore
对象semaphore
,初始值为 3,表示最多允许 3 个线程同时访问资源。 创建 5 个线程,每个线程执行的任务是:
- 尝试获取许可,如果没有可用的许可,线程会被阻塞,直到有许可可用。
- 打印获取到许可的信息。
- 模拟线程执行一段时间(这里使用
Thread.sleep(2000)
模拟)。 - 打印线程执行完毕的信息。
- 释放许可。
- 启动线程,让它们开始执行任务。
可能的输出结果:
Thread-1 获取到许可
Thread-2 获取到许可
Thread-3 获取到许可
Thread-1 执行完毕
Thread-1 释放许可
Thread-2 执行完毕
Thread-2 释放许可
Thread-3 执行完毕
Thread-3 释放许可
Thread-4 获取到许可
Thread-4 执行完毕
Thread-4 释放许可
Thread-5 获取到许可
Thread-5 执行完毕
Thread-5 释放许可
在这个示例中,最多允许 3 个线程同时获取许可,其他线程需要等待有许可可用时才能获取。每个线程获取到许可后,执行一段时间后释放许可。请注意,输出的顺序可能会有所不同,因为线程的执行顺序是不确定的。
Semaphore 代码示例 2 :
下面是一个使用 Semaphore 模拟抢占停车位的代码示例:
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreDemo {
public static void main(String[] args) {
// 创建一个 Semaphore 对象,初始值为 3,表示停车场有 3 个车位
Semaphore semaphore = new Semaphore(3);
// 创建 6 个线程模拟 6 辆汽车
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
try {
// 尝试抢占车位
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "\t抢到车位");
try {
// 停留 3 秒
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t停留 3 秒后离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放车位
semaphore.release();
}
}, "汽车" + i).start();
}
}
}
代码解析:
- 创建一个
Semaphore
对象semaphore
,并将初始值设为 3,表示停车场有 3 个车位。 - 使用
for
循环创建 6 个线程,模拟 6 辆汽车。 每个线程执行的任务是:
- 尝试通过
semaphore.acquire()
抢占车位。如果车位已满,线程会被阻塞,直到有车位可用。 - 打印抢到车位的信息。
- 停留 3 秒钟,使用
TimeUnit.SECONDS.sleep(3)
模拟停留时间。 - 打印停留 3 秒后离开车位的信息。
- 通过
semaphore.release()
释放车位。
- 尝试通过
- 启动线程,让它们开始执行任务。
可能的打印结果:
汽车3 抢到车位
汽车2 抢到车位
汽车1 抢到车位
汽车3 停留 3 秒后离开车位
汽车1 停留 3 秒后离开车位
汽车2 停留 3 秒后离开车位
汽车6 抢到车位
汽车4 抢到车位
汽车5 抢到车位
汽车6 停留 3 秒后离开车位
汽车4 停留 3 秒后离开车位
汽车5 停留 3 秒后离开车位
请注意,由于线程的执行顺序是不确定的,实际的输出顺序可能会有所不同。但是,无论输出顺序如何,最终每辆汽车都会抢到车位、停留 3 秒后离开。最多只能有 3 辆汽车同时停在停车位上,其他汽车需要等待前面的汽车离开才能抢占车位。
Semaphore 底层原理涉及到线程同步和共享变量的操作
Semaphore是Java.util.concurrent包中提供的一个线程同步工具类,它可以用来控制同时访问某个资源的线程数量。Semaphore内部使用了共享模式,并基于AQS(AbstractQueuedSynchronizer)来实现线程的同步和互斥。
Semaphore的底层原理是基于AQS的共享模式实现的。AQS维护了一个共享的同步状态(state)和一个等待队列。Semaphore中的同步状态表示可用的许可证的数量,而等待队列中的线程表示等待获取许可证的线程。
具体来说,Semaphore的主要方法是acquire()和release()。当一个线程调用acquire()方法时,会尝试获取一个许可证,即将同步状态的值减1。如果此时同步状态的值大于等于0,则表示成功获取到许可证,线程可以继续执行后续的代码。如果同步状态的值小于0,则表示许可证已经全部被占用,线程会进入阻塞状态,被加入到等待队列中。
当有一个线程调用release()方法时,会释放一个许可证,即将同步状态的值加1。如果此时等待队列中有等待获取许可证的线程,它们会被唤醒并尝试再次获取许可证。如果没有等待的线程,许可证会被存储在Semaphore中,供后续的acquire()方法调用使用。
Semaphore的底层原理与CountDownLatch和CyclicBarrier有所不同。CountDownLatch和CyclicBarrier都是基于AQS的共享模式实现的,但它们的同步状态是通过计数器实现的。而Semaphore的同步状态是表示可用的许可证的数量。通过控制许可证的数量,就可以控制同时访问某个资源的线程数量。
总结起来,Semaphore使用AQS的共享模式来实现线程的同步和互斥。通过控制许可证的数量,Semaphore可以限制同时访问某个资源的线程数量。它可以应用于线程池、资源池等场景,实现对资源的有效利用和线程的合理调度。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。