基本概念
Semaphore 信号标的意思,作用其实就是限流,构造方法中可以传一个参数permits表示允许同时执行线程的数量。也可看成是信号标、许可标记的数量。
semaphore.acquire()是阻塞方法,获取不到信号标就阻塞,获取到的话信号标permits会减1。
比如Semaphore semaphore = new Semaphore(1),一个线程semaphore.acquire()成功后,许可标记1会变成0,这时其它线程无法获得许可标记,acquire()方法会阻塞。当线程执行完后必须手动semaphore.release()释放标记,这时许可标记会从0变成1,其它线程acquire()到后可以继续执行。
举个栗子
举个例子,比如去窗口买票,new Semaphore(3)就表示有3个窗口,一个人抢先到了某个窗口前就表示acquire到了许可。3个窗口占满后别人只能等着,等有人买完票让出窗口release后才能占住窗口买票。
Semaphore默认是非公平的,new Semaphore(2, true) 第二个参数为true可设置成公平的。
公平就是有队列在那里等,需要执行的线程要先排队。用收费站来举例,假如有四辆车都在等着进一个车道,当后面再来一辆的时候,它不会超到前面去,而是要在后面排着,这叫公平。
内部实现公平锁用的AQS
所以说内部是有队列的。此外reentrantlock、CountDownLatch、CyclicBarrier、Phaser、ReadWriteLock、Semaphore、Exchanger都是用同一个队列,同一个类来实现的,这个类叫AQS。
示例程序
public class T06_Semaphore {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(2, true);
// Semaphore semaphore = new Semaphore(1); // 允许一个线程同时执行
new Thread(() -> {
try {
semaphore.acquire();
System.out.println("thread1 start...");
TimeUnit.SECONDS.sleep(1);
System.out.println("thread1 end...");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}).start();
new Thread(() -> {
try {
semaphore.acquire();
System.out.println("thread2 start...");
TimeUnit.SECONDS.sleep(1);
System.out.println("thread2 end...");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}).start();
}
}
网友评论