信号量模型

信号量模型

java在1.5以后引入了Semaphore 信号量模型,放在concurrent包下面用来解决同步协作问题。

即解决两个基本问题

  • 多个共享资源互斥使用
  • 并发线程数的控制

“计数信号量(Counting Semaphore)用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量。计数信号量还可以用来实现某种资源池,或者对容器施加边界。”

“Semaphore中管理着一组虚拟的许可(permit),许可的出事量可以通过构造函数来指定。在执行操作是可以首先获得许可(只要还有剩余的许可),并在使用以后释放许可。如果没有许可,那么acquire将阻塞直到有许可(或者直到被中断或者操作超时)。release方法将返回一个许可给信号量。计算信号量的一种简化形式是二值信号量,即初始值为1的Semaphore。二值信号量可以用作互斥(mutex),并具备不可重入的加锁语义:谁拥有这个唯一的许可,谁就拥有了互斥锁。”

“概念上讲,一个信号量管理许多的许可证(permit)。为了通过信号量,线程通过调用acquire请求许可。其实没有实际的许可对象,信号量仅维持一个计数。许可的数目是固定的,由此限制了通过的线程数量。其他线程可以通过调用release释放许可。而且,许可必须由获取它的线程释放。事实上,任何线程都可以释放任意数目的许可,这可能会增加许可数目以至于超出初始数目。”

Semaphore的使用

先看一个例子:

public class SemaphoreDemo {
    private int n;
    public SemaphoreDemo(int n) {
        this.n = n;
    }
    Semaphore ever = new Semaphore(1);
    int i = 1;
    public void even(IntConsumer printNumber) throws InterruptedException {
        while (i <= n) {
            ever.acquire();
            if (i % 2 == 1 && i <= n) {
                printNumber.accept(i);
                i++;
            }
            ever.release();
        }
    }

    public void odd(IntConsumer printNumber) throws InterruptedException {
        while (i <= n) {
            ever.acquire();
            if (i % 2 == 0 && i <= n) {
                printNumber.accept(i);
                i++;
            }
            ever.release();
        }
    }

    public static void main(String[] args) {
        SemaphoreDemo semaphoreDemo = new SemaphoreDemo(100);
        new Thread(() -> {
            try {
                semaphoreDemo.even(i -> System.out.println("" + i));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(() -> {
            try {
                semaphoreDemo.odd(i -> System.out.println("" + i));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

这个例子调用两个线程分表交替打印奇偶数。这就是利用了信号对资源共享进行互斥使用。

第二个例子:

public static void main(String[] args){
        Semaphore se=new Semaphore(5);
        for(int i=0;i<=20;i++){
            new Thread(()->{
                try {
                    se.acquire();
                    System.out.println(Thread.currentThread().getName()+"\t 我占了个座");
                    TimeUnit.SECONDS.sleep((int)Math.random()*10+1);
                    System.out.println(Thread.currentThread().getName()+"\t 我用完了");
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    se.release();
                }
            }).start();
        }
    }

通过令牌数量的控制,限制了并发线程的数量。

上一篇:JUC强大的辅助类讲解--->>>CyclicBarrier(信号灯)


下一篇:AB实验的高端玩法系列2 - 更敏感的AB实验, CUPED!