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的构造方法参数,并非是最终许可数,恰恰相反它是许可数的初始状态.
欢迎关注下面二维码进行技术交流: