多线程进阶之并发工具类第二篇:Semaphore、Exchanger

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)设置最大等待时长。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值