synchronized的语义是互斥锁,就是在同一时刻,只有一个线程能获得执行代码的锁。但是现实生活中,有好多的场景,锁不止一把。
比如说,又到了十一假期,买票是重点,必须圈起来。在购票大厅里,有5个售票窗口,也就是说同一时刻可以服务5个人。要实现这种业务需求,用synchronized显然不合适。
查看Java并发工具,发现有一个Semaphore类,天生就是处理这种情况的。
先用Semaphore实现一个购票的小例子,来看看如何使用
package semaphore;
import java.util.concurrent.Semaphore;
public class Ticket {
public static void main(String[] args) {
Semaphore windows = new Semaphore(5); // 声明5个窗口
for (int i = 0; i < 8; i++) {
new Thread() {
@Override
public void run() {
try {
windows.acquire(); // 占用窗口
System.out.println(Thread.currentThread().getName() + ": 开始买票");
sleep(2000); // 睡2秒,模拟买票流程
System.out.println(Thread.currentThread().getName() + ": 购票成功");
windows.release(); // 释放窗口
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
}
运行结果
Thread-1: 开始买票 Thread-3: 开始买票 Thread-4: 开始买票 Thread-2: 开始买票 Thread-0: 开始买票 Thread-1: 购票成功 Thread-5: 开始买票 Thread-3: 购票成功 Thread-2: 购票成功 Thread-4: 购票成功 Thread-7: 开始买票 Thread-6: 开始买票 Thread-0: 购票成功 Thread-7: 购票成功 Thread-5: 购票成功 Thread-6: 购票成功
View Code
从结果来看,最多只有5个线程在购票。而这么精确的控制,我们也只是调用了acquire和release方法。下面看看是如何实现的。