1.Semaphore工具类, ['seməfɔːr],是信号灯的意思,用来控制同时访问特定资源的线程的数量。
举个例子,比如XX桥因为年久失修,要限制车数量,只允许同时最多有100辆车在桥上行驶,其他必须在路口等待,所以前100辆车会看到绿灯,可以开上桥,后面的车会看到红灯,不能开上桥。但是前面100辆车如果有5辆车已经下了桥,那么后面就允许有5辆车再开上桥。这个例子中的车就是线程,开上桥就表示线程在执行,开下桥就表示线程执行完成,看见红灯就表示线程处于阻塞状态,不能执行。
常用在公共资源有限的场景,比如说获取数据库连接。假设有30个线程要写数据库,而数据库连接池最多有10个连接,则必须控制最多同时有10个线程获取数据库连接,否则会报无法获取数据库连接异常:
public class SemaphoreTest {
static ExecutorService executorService = Executors.newFixedThreadPool(30);
static Semaphore s = new Semaphore(10, true);
public static void main(String[] args) {
for (int i = 0; i < 30; i++) {
executorService.submit(new Runnable() {
public void run() {
try {
// 获取许可证
if (s.tryAcquire()) {
// 获取数据库连接,储存数据后,释放数据库连接
System.out.println(Thread.currentThread().getName() + " save data");
// 释放许可证
s.release();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
executorService.shutdown();
}
}
以上,用Semaphore(int permits)的构造器创建了一个最多同时支持10个线程工作的Semaphore实例,在线程方法体中调用此Semaphore实例的tryAcquire()方法尝试获取一个许可证,如果获取到许可证,则操作数据库,之后再调用此Semaphore实例的release()方法释放通行证。Semaphore还有一些对象方法跟许可证有关,如int availablePermits()返回当前可用的许可证数,int getQueueLength()返回正在等待等待许可证的线程数,等等。
2.Exchanger工具类
Exchanger用于两个线程间的数据交换。两个线程通过V Exchanger实例的exchange(V x)方法交换数据,如果第一个线程先执行V exchange(V x)方法,它会一直等待第二个线程也执行V exchange(V x)方法,当第二个线程也执行完V exchange(V x)方法后,两个线程就将本线程的数据传递给对方,从而完成数据交换,V exchange(V x)方法的返回值即为交换后的数据:
public class ExchangerTest {
private static final Exchanger<String> exchanger = new Exchanger<String>();
private static ExecutorService executor = Executors.newFixedThreadPool(2);
public static void main(String[] args) {
executor.submit(new Runnable() {
public void run() {
String A = "银行流水A";
try {
String exchangeA = exchanger.exchange(A);
System.out.println("exchangeA:" + exchangeA);
} catch (Exception e) {
e.printStackTrace();
}
}
});
executor.submit(new Runnable() {
public void run() {
String B = "银行流水B";
try {
String exchangeB = exchanger.exchange(B);
System.out.println("exchangeB:" + exchangeB);
System.out.println("A和B数据是否一致:" + exchangeB.equals(B));
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
如果两个线程有一个没有执行exchange(V x)方法,则会一直等待,如果担心有特殊情况发生,避免一直等待,可以使用V exchange(V x, long timeout, TimeUnit unit)设置最大等待时长。