Semaphore:该类的主要作用是限制线程并发的数量,
为什么要限制并发的数量?
因为CPU资源有限,如果是多个线程同时运行,CPU要把时间片分配给不同的线程对象,
而且上下切换时特别耗时,最终会导致系统运行效率降低。
类Semaphore的构造方法
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
参数permits是允许,许可的意思,代表同一时间内,
最多允许多少个线程执行acquire()和release()之间的代码。

private Semaphore semaphore=new Semaphore(1);
表示同一时间内最多只有1个线程可以执行acquire()和release()之间的代码。

当permits大于1时,表示同一时间内,最多允许有x个线程可以执行acquire()和release()之间的代码。
当permits大于1时,该类无法保证线程安全,因为有可能出现多个线程共同访问实例变量,导致数据变脏.
acquire()无参数,表示占用1个许可

acquire(int permits)有参方法,每调用1次该方法,就会使用permits个许可.
release()无参数,表示增加1个许可
release(int permits)有参方法,每调用1次该方法,就会增加permits个许可.

案例代码如下:

public class Service {
    private Semaphore semaphore=new Semaphore(1);
    public void test(){
        try {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName()
                    +" 开始时间="+System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println(Thread.currentThread().getName()
                    +" 结束时间="+System.currentTimeMillis());
            //System.out.println("availablePermits_"+Thread.currentThread().getName()+"="+semaphore.availablePermits());
            semaphore.release();
            //System.out.println("availablePermits_"+Thread.currentThread().getName()+"="+semaphore.availablePermits());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

线程类

public class Thread_A extends Thread {
    private Service service;
    public Thread_A(Service service){
        super();
        this.service=service;
    }
    public void run(){
        service.test();
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        Service service=new Service();
        Thread_A a=new Thread_A(service);
        a.setName("A");
        Thread_B b=new Thread_B(service);
        b.setName("B");
        Thread_C c=new Thread_C(service);
        c.setName("C");
        a.start();
        b.start();
        c.start();
    }
}

测试结果:

A 开始时间=1501977937514
A 结束时间=1501977942516
B 开始时间=1501977942516
B 结束时间=1501977947526
C 开始时间=1501977947526
C 结束时间=1501977952532

改变1:
acquire(int permits)有参方法,每调用1次该方法,就会使用permits个许可.
将上述案例中其他类不改变只改变Service类中下面两处:
release()无参数,表示增加1个许可
release(int permits)有参方法,每调用1次该方法,就会增加permits个许可.

Semaphore semaphore=new Semaphore(3);
...
semaphore.acquire(2);

可得结果为:

A 开始时间=1501974670443
A 结束时间=1501974675443
B 开始时间=1501974675443
B 结束时间=1501974680443

分析:

Semaphore类总共有3个许可,表示同一时间允许3个许可用在执行代码块M,
而acquire的参数为2,表示每次调用该方法就会占用2个许可,
故:3/2=1余1:表示同一时间只有1个线程执行代码块M,
所以A线程先执行,当A线程结束前,会调用release(),增加一个许可,
由于之前剩余一个许可,剩余许可加上增加的许可刚好两个许可,便执行B线程,
当B线程执行完毕时增加1个许可,但由于没有其他许可剩余,故C线程无法执行.

改变2:

其他地方不变,只将Semaphore的构造参数改为4,则A、B、C线程便可全部执行
    B 开始时间=1501976068531
    A 开始时间=1501976068531
    A 结束时间=1501976073532
    B 结束时间=1501976073532
    C 开始时间=1501976073532
    C 结束时间=1501976078532

改变3:

其他地方不变,semaphore.release(permits),permits>2,则A、B、C线程也可全部执行:
    A 开始时间=1501976300912
    A 结束时间=1501976305922
    B 开始时间=1501976305922
    C 开始时间=1501976305922
    B 结束时间=1501976310922
    C 结束时间=1501976310922
availablePermits()可以当前可用的许可
说明:Semaphore的构造方法参数,并非是最终许可数,恰恰相反它是许可数的初始状态.

欢迎关注下面二维码进行技术交流:
Java 并发编程笔记(一)_java并发