原创转载请注明出处:http://agilestyle.iteye.com/blog/2342878
Semaphore所提供的功能完全是synchronized关键字的升级版,但它提供的功能更加的强大和方便,主要的作用是控制线程并发的数量。
Semaphore(int permits)
设置permits为1
Service.java
package org.fool.java.concurrent.semaphore; import java.util.concurrent.Semaphore; public class Service { private Semaphore semaphore = new Semaphore(1); public void testMethod() { try { semaphore.acquire(); System.out.println(Thread.currentThread().getName() + " begin timer=" + System.currentTimeMillis()); Thread.sleep(5000); System.out.println(Thread.currentThread().getName() + " end timer=" + System.currentTimeMillis()); semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } } }
Note:
permits代表同一时间内,最多允许多少个线程同时执行acquire()和release()之间的代码。
本例设置为1,所以最多只有1个线程同时执行acquire()和release()之间的代码。
ThreadA.java
package org.fool.java.concurrent.semaphore; public class ThreadA implements Runnable { private Service service; public ThreadA(Service service) { this.service = service; } @Override public void run() { service.testMethod(); } }
ThreadB.java
package org.fool.java.concurrent.semaphore; public class ThreadB implements Runnable { private Service service; public ThreadB(Service service) { this.service = service; } @Override public void run() { service.testMethod(); } }
ThreadC.java
package org.fool.java.concurrent.semaphore; public class ThreadC implements Runnable { private Service service; public ThreadC(Service service) { this.service = service; } @Override public void run() { service.testMethod(); } }
SemaphoreTest.java
package org.fool.java.concurrent.semaphore; public class SemaphoreTest { public static void main(String[] args) { Service service = new Service(); Thread a = new Thread(new ThreadA(service)); Thread b = new Thread(new ThreadA(service)); Thread c = new Thread(new ThreadA(service)); a.setName("A"); b.setName("B"); c.setName("C"); a.start(); b.start(); c.start(); } }
Run
Note:
private Semaphore semaphore = new Semaphore(1);
由于定义了最多1个线程执行acquire()和release()之间的代码,所以打印的结果就是3个线程是同步的,线程A执行结束的时间和线程B执行开始的时间相同,线程B执行结束的时间和线程C还行开始的时间相同。
修改Service.java,设置permits为2
private Semaphore semaphore = new Semaphore(2);
再次Run SemaphoreTest
Note:
由于定义了最多2个线程执行acquire()和release()之间的代码,所以线程A和线程B执行开始的时间是相同的,需要注意的是,对Semaphore的构造方法传递的参数permits值如果大于1时,该类并不能保证线程的安全性,因为还是有可能会出现多个线程共同访问实例变量,导致出现脏读。
Semaphore(int permits, boolean fair)
有些时候,获得permits的顺序与线程启动的顺序有关,这时信号量就要分为公平和非公平的。
公平信号量是获得锁的顺序与线程启动的顺序有关,但不代表100%地获得信号量,仅仅是在概率上能得到保证。
非公平信号量即获得锁的顺序与线程启动的顺序无关。
Service.java
package org.fool.java.concurrent.semaphore.fair; import java.util.concurrent.Semaphore; public class Service { private boolean isFair = false; private Semaphore semaphore = new Semaphore(1, isFair); public void testMethod() { try { semaphore.acquire(); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } } }
Note:
设置了非公平信号量
private boolean isFair = false;
ThreadA.java
package org.fool.java.concurrent.semaphore.fair; public class ThreadA implements Runnable { private Service service; public ThreadA(Service service) { this.service = service; } @Override public void run() { System.out.println(Thread.currentThread().getName() + " invoked..."); service.testMethod(); } }
FairTest.java
package org.fool.java.concurrent.semaphore.fair; public class FairTest { public static void main(String[] args) { Service service = new Service(); Thread a = new Thread(new ThreadA(service)); a.start(); for(int i = 0; i < 4; i++) { new Thread(new ThreadA(service)).start(); } } }
Run
非公平信号量运行的效果是线程启动的顺序与调用semaphore.acquire()的顺序无关,也就是线程先启动了并不代表获得permits
修改Service.java,设置公平信号量
private boolean isFair = true;
再Run
公平信号量运行的效果是线程启动的顺序与调用semaphore.acquire()的顺序有关,也就是先启动的线程优先获得permits