《Java并发编程》--- 8 并发工具类

本文深入解析Java中的四个关键并发工具类:CountDownLatch、CyclicBarrier、Semaphore和Exchanger,涵盖其基本概念、构造方法、核心功能及应用场景,帮助读者掌握线程间同步与协作的高级技巧。

8 Java中的并发工具类

8.1 CountDownLatch
  • 允许一个或多个线程等待其他线程完成操作,具有join的功能,比join的功能更多。
  • 构造函数CountDownLatch(int N),int型参数作为计数器,可以是N个线程,也可以是1个线程里的N个执行步骤。

    CountDownLatch不可能重新初始化或者修改CountDownLatch对象内部计数器的值。

  • 调用CountDownLatch的countDown()方法时,N就会减一;CountDownLatch的await()方法会阻塞当前线程,直到N变成0。
  • 当等待的线程处理过慢,不能让主线程一直等待,可以使用待指定时间的await(long time, TimeUnit unit),等待特定时间后不再阻塞当前线程。
8.2 CyclicBarrier
  • 可循环使用屏障。作用是让一组线程到达一个屏障(同步点)时被阻塞,直到最后一个线程到达屏障,屏障才会开门,所有被屏障拦截的线程才会继续运行。

  • 默认构造方法 CyclicBarrier(int parties),参数表示屏障拦截的线程数量。每个线程调用await方法告诉CyclicBarrier已经达到了屏障,然后当前线程被阻塞。

  • 高级构造函数CyclicBarrier(int parties, Runnable barrierAction),用于线程到达屏障时,优先执行barrierAction,方便处理更复杂的业务场景。

  • CyclicBarrier的计数器可以使用reset()方法重置。

    可以处理更复杂的业务场景,例如计算错误可以重置计数器重新执行一次。

  • 其他方法如getNumberWaiting方法可获得阻塞的线程数,isBroken()方法用来了解阻塞的线程是否被中断。

  • 应用场景:用于多线程计算数据,最后合并计算结果。(主线程等待各个部分数据计算完成后,开始合并数据)

    银行流水统计:一个Excel里有4个sheet,每个sheet有一年的银行流水。

    import java.util.Map.Entry;
    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.CyclicBarrier;
    import java.util.concurrent.Executor;
    import java.util.concurrent.Executors;
    
    public class BankWaterService implements Runnable{
    	//创建4个屏障,处理完之后执行当前类的run方法
    	private CyclicBarrier c= new CyclicBarrier(4,this);
    
    	//启动固定数量=4的线程池
    	private Executor executor = Executors.newFixedThreadPool(4);
    	//保存4个sheet的计算数据
    	private ConcurrentHashMap<String, Integer> sheetBankWaterCount = new ConcurrentHashMap<>();
    	
    	private void count(){
    		for(int i = 0; i < 4; i++){
    			//将任务放进线程池
    			executor.execute(new Runnable(){
    				@Override 
    				public void run(){
    					/*计算流水数据,过程省略,假设结果=1,放进chm中*/
    					sheetBankWaterCount.put(Thread.currentThread().getName(), 1);
    					//计算完成,插入一个屏障
    					try{
    						c.await();
    					}
    					catch(InterruptedException|BrokenBarrierException e){
    						e.printStackTrace();
    					}
    				}
    			});
    		}
    	}
    	
    	/*当前线程的run方法,汇总sheet结果
    	等待之前的线程执行完成,全都调用await()方法通知之后才能开始执行。
    	*/
    	@Override
    	public void run(){
    		int result = 0;
    		for(Entry<String, Integer> entry:sheetBankWaterCount.entrySet()){
    			result = result + entry.getValue();
    		}
    		sheetBankWaterCount.put("result", result);
    		//打印
    	}
    
    	public static void main(String[] args){
    		BankWaterService service = new BankWaterService();
    		service.count();
    	}
    }
    
8.3 Semaphore
  • Semaphore信号量,用来控制同时访问特定资源的线程数量。
  • 用来做流量控制,特别是共用资源有限的应用场景,比如数据库链接。
  • Semaphore(int permits)构造方法,表示许可证数量。
    Semaphore(int permits, boolean fair)指定公平还是非公平获取。
  • Semaphore的acquire()/tryAcquire()方法获取一个许可证,使用完之后调用release()方法归还。

    acquire():响应中断,没有可用的许可证时当前线程被阻塞
    acquireUninterruptibly():不响应中断
    tryAcquire():尝试获取许可证(非公平),立即返回结果(非阻塞)
    tryAcquire(long timeout, TimeUnit unit):尝试获取许可证(定时获取)
    底层实现是AQS里面的抽象方法tryAcquireShared。

8.4 Exchanger
  • 用于线程间的协作的工具类,进程线程间的数据交换。提供一个同步点,在这个同步点两个线程可以交换彼此的数据,通过exchange()方法。

    线程A限制性exchange()方法,会一直等待线程B也执行exchange()方法,当两个线程都到达同步点时,交换数据。如果有一个没有执行,则会一直等待。可以使用exchange(long timeout, TimeUnit unit)设置最大等待时间。

    可简单地将Exchanger对象理解为一个包含两个格子的容器,通过exchanger方法可以向两个格子中填充信息。当两个格子中的均被填充时,该对象会自动将两个格子的信息交换,然后返回给线程,从而实现两个线程的信息交换。

  • 应用场景:遗传算法中需要选出两个人作为交配对象,交换两人数据,并使用交叉规则得出两个交配结果。
    用于校对工作,两人录入相同数据,对数据进行校对是否一致。

  • 示范:

import java.util.concurrent.Exchanger;
 
class ExchangerTest extends Thread {
    private Exchanger<String> exchanger;
    private String string;
    private String threadName;
 
    public ExchangerTest(Exchanger<String> exchanger, String string, String threadName) {
        this.exchanger = exchanger;
        this.string = string;
        this.threadName = threadName;
    }
 
    public void run() {
        try {
        	//exchanger.exchange(string)填充进exchanger
            System.out.println(threadName + ": " + exchanger.exchange(string));
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
 
public class Test {
    public static void main(String[] args) {
    	/*调用同一个exchanger对象的exchange方法,进行信息通信
    	当两个线程均已将信息放入到exchanger对象中时,exchanger对象会将两个线程放入的信息交换,然后返回
    	*/
        Exchanger<String> exchanger = new Exchanger<>();
        ExchangerTest test1 = new ExchangerTest(exchanger, "str1", "thread1");
        ExchangerTest test2 = new ExchangerTest(exchanger, "str2", "thread2");
 
        test1.start();
        test2.start();
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值