Semaphore
Semaphore是一个计数信号量。
从概念上将,Semaphore包含一组许可证。
如果有需要的话,每个acquire()方法都会阻塞,直到获取一个可用的许可证。
每个release()方法都会释放持有许可证的线程,并且归还Semaphore一个可用的许可证。
然而,实际上并没有真实的许可证对象供线程使用,Semaphore只是对可用的数量进行管理维护
总结:如果线程要访问一个资源就必须先获得信号量。如果信号量内部计数器大于0,信号量减1,然后允许共享这个资源;否则,如果信号量的计数器等于0,信号量将会把线程置入休眠直至计数器大于0.当信号量使用完时,必须释放
1114. 按序打印(简单)
class Foo {
Semaphore s12 = new Semaphore(0);
Semaphore s23 = new Semaphore(0);
public Foo() {
}
public void first(Runnable printFirst) throws InterruptedException {
printFirst.run();
s12.release();//释放后s12的值会变成1
}
public void second(Runnable printSecond) throws InterruptedException {
s12.acquire();//没有会阻塞 当为1的时候,说明线程2可以拿到s12了
printSecond.run();
s23.release();//释放后s23的值会变成1
}
public void third(Runnable printThird) throws InterruptedException {
s23.acquire();//0的时候拿不到,1的时候可以拿到
printThird.run();
}
}
1115. 交替打印 FooBar(中等)
class FooBar {
private int n;
private Semaphore fooSema = new Semaphore(1);
private Semaphore barSema = new Semaphore(0);
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
fooSema.acquire();//值为1的时候,能拿到,执行下面的操作
printFoo.run();
barSema.release();//释放许可给barSema这个信号量 barSema 的值+1
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
barSema.acquire();//值为1的时候,能拿到,执行下面的操作
printBar.run();
fooSema.release();//释放许可给fooSema这个信号量 fooSema 的值+1
}
}
}
1116. 打印零与奇偶数(中等)
class ZeroEvenOdd {
private int n;
private Semaphore zeroSema = new Semaphore(1);
private Semaphore oddSema = new Semaphore(0);//奇数
private Semaphore evenSema = new Semaphore(0);//偶数
public ZeroEvenOdd(int n) {
this.n = n;
}
public void zero(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i++) {
zeroSema.acquire();
printNumber.accept(0);
if ((i & 1) == 1) {//奇数
oddSema.release();
} else {
evenSema.release();
}
}
}
public void even(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i++) {
if ((i & 1) == 0) {//偶数 打印偶数 并释放zero的线程
evenSema.acquire();
printNumber.accept(i);
zeroSema.release();
}
}
}
public void odd(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i++) {
if ((i & 1) == 1) {//奇数,打印奇数,并释放zero的线程
oddSema.acquire();
printNumber.accept(i);
zeroSema.release();
}
}
}
}
1195. 交替打印字符串(中等)
class FizzBuzz {
private int n;
private Semaphore f;
private Semaphore b;
private Semaphore fB;
private Semaphore num;
public FizzBuzz(int n) {
this.n = n;
num = new Semaphore(1);
f = new Semaphore(0);
b = new Semaphore(0);
fB = new Semaphore(0);
}
// printFizz.run() outputs "fizz".
public void fizz(Runnable printFizz) throws InterruptedException {
for (int i = 1; i <= n; i++) {
if (i % 3 == 0 && i % 5 != 0) {
f.acquire();
printFizz.run();
num.release();
}
}
}
// printBuzz.run() outputs "buzz".
public void buzz(Runnable printBuzz) throws InterruptedException {
for (int i = 1; i <= n; i++) {
if (i % 5 == 0 && i % 3 != 0) {
b.acquire();
printBuzz.run();
num.release();
}
}
}
// printFizzBuzz.run() outputs "fizzbuzz".
public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
for (int i = 1; i <= n; i++) {
if (i % 5 == 0 && i % 3 == 0) {
fB.acquire();
printFizzBuzz.run();
num.release();
}
}
}
// printNumber.accept(x) outputs "x", where x is an integer.
public void number(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i++) {
num.acquire();
if (i % 3 != 0 && i % 5 != 0) {
printNumber.accept(i);
num.release();
} else if (i % 3 == 0 && i % 5 == 0) {
fB.release();
} else if (i % 3 == 0) {
f.release();
} else if (i % 5 == 0) {
b.release();
}
}
}
}
交替输出数字(信号量机制)
public class AppTest {
private Semaphore first;
private Semaphore second;
public AppTest() {
first = new Semaphore(1);
second = new Semaphore(0);
}
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue() throws InterruptedException {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
if (i % 2 == 1) {
try {
first.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread1---" + i);
second.release();
}
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
if (i % 2 == 0) {
try {
second.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread2---" + i);
first.release();
}
}
}
});
thread1.start();
thread2.start();
Thread.sleep(Integer.MAX_VALUE);
}
}