java 多线程协调工具类 笔记

算法思想–>Fork/Join–分而治之

大问题—>分割成小问题, 小问题之间无关联 -->分而治之
A, a1,a2,a3,a4–>a1(a3) , a2(a4) , 问题之间有依赖, -->动态规划

forkJoin中的工作密取:当同时存在多个任务线程,有线程先完成,那么先完成的线程从未完成的任务列表尾部取一部分处理,处理完成后再放回去

ForkJoin,如何使用

  1. RecursiveTask(递归任务)/RecursiveAction/ForkJoinTask
    任务拆分到最小后处理完,再以Join方法合并结果,没返回值的用(Action),有返回值的用(Task)
  2. pool 同步提交 invoke
    异步提交 submit, execute

实例:统计一个大数组中的数字之和----同步返回结果

//创建一个大数组
int[] bigArr = {...........};
//创建ForkJoin任务池
ForkJoinPool pool = new ForkJoinPool();
//创建任务实例
SumTask task = new SumTask(bigArr,0,bigArr.length-1);
pool.invoke(task);

//结果
Integer result = task.join();

SumTask类

public class SumTask extends RecursiveTask<Ingeger>{
	//阈值
	private final static int THRESHOLD = 100;
	private int[] src;
	private int fromIndex,toIndex;
	public SumTask(int[] src,int fromIndex,int toIndex){
		this.src = src;
		this.fromIndex = fromIndex;
		this.toIndex = toIndex;
	}
	@Override
	protected Integer compute(){
		//判断任务大小是否合适
		if(toIndex-fromIndex<THRESHOLD){//大小合适
			int count=0;
			for(int i=0;i<src.length;i++){
			 	count +=src{i};
			}
			return count;
		}else{//切分任务
			int mid = (fromIndex+toIndex)/2;
			SumTask ta1 = new SumTask(src,fromIndex,mid);
			SumTask ta2 = new SumTask(src,mid+1,toIndex);
			invokeAll(ta1,ta2);
			return ta1.join()+ta2.join();
		}
	}
}

实例:归并排序----同步返回结果

	public static class RecursiveSortTask extends RecursiveTask<Integer[]>{
		private int threshold = 100;//任务组大小阈值
		private int startIndex = 0;
		private int endIndex = 0;
		private Integer[] src;
		public RecursiveSortTask(Integer[] src,int start,int end) {
			this.src = src;
			this.startIndex = start;
			this.endIndex = end;
		}
		@Override
		protected Integer[] compute() {
			if(endIndex-startIndex<=threshold) {//不满足阈值的,直接排序
				Integer[] _temp = Arrays.copyOfRange(src, startIndex, endIndex+1);
				if(_temp.length<2) {
					return _temp;
				}
				//倒序
				for(int i=0;i<_temp.length-1;i++) {
					for(int j=0;j<_temp.length-1-i;j++) {
						if(_temp[j]<_temp[j+1]) {
		                    int temp = _temp[j];
		                    _temp[j]=_temp[j+1];
		                    _temp[j+1]=temp;
						}
					}
				}
				//System.out.println(startIndex+"--"+endIndex+"-->"+String.join(",",Arrays.asList(_temp).stream().map(t->t+"").collect(Collectors.toList())));
				return _temp;
			}else {
				int mid = (startIndex+endIndex)/2;
				RecursiveSortTask ta1 = new RecursiveSortTask(src, startIndex, mid);
				RecursiveSortTask ta2 = new RecursiveSortTask(src, mid+1,endIndex);
				invokeAll(ta1,ta2);
				//合并结果集
				Integer[] _temp1 = ta1.join();
				Integer[] _temp2 = ta2.join();
				int totalCount = _temp1.length+_temp2.length;
				Integer[] _result = new Integer[totalCount];
				int a1 =0,a2=0;
				for(int i=0;i<totalCount;i++) {
					if(a1==_temp1.length) {//表示1数组已取完
						_result[i] = _temp2[a2];
						a2++;
						continue;
					}
					if(a2==_temp2.length) {//表示2数组已取完
						_result[i] = _temp1[a1];
						a1++;
						continue;
					}
					if(_temp1[a1]>=_temp2[a2]) {
						_result[i] = _temp1[a1];
						a1++;
					}else {
						_result[i] = _temp2[a2];
						a2++;
					}
				}
				
				return _result;
			}
		}
	}
	public static void main(String[] args) {
		int count = 100000;
		Integer[] _temp = new Integer[count];
		for(int i =0;i<count;i++) {
			_temp[i] = Double.valueOf(Math.random()*count).intValue();
		}
		ForkJoinPool pool = new ForkJoinPool();
		RecursiveSortTask task = new RecursiveSortTask(_temp, 0, _temp.length-1);
		pool.invoke(task);
		pool.invoke(task);
		_temp = task.join();
		
		System.out.println(String.join(",",Arrays.asList(_temp).stream().map(t->t+"").collect(Collectors.toList())));
	}

实例:遍历目录找文件异步返回结果


StampedLock 高性能读写锁

乐观读锁:
	获取读锁时不加锁,直接返回一个值,执行临界区的时候去验证这个值是否被修改(写锁加锁)
	如果没被修改,则直接执行临界区代码,如果被修改则升级为读写锁(ReentrantReadWriteLock-->ReadLock)
StampedLock lock = new StampedLock();
long stamp = lock.tryOptimisticRead();

if(lock.validate(stamp)){//验戳	
	....
	return ;
}
//验证失败
try{//锁升级
	stamp = lock.readLock();
	...业务代码
	return ;
}finally{
	lock.unlockWrite(stamp);
}


CountDownLatch 类,闭锁—底层AQS
用处:相当于发令枪一样,等一定数量线程都执行完一定初始化工作,然后调用await()之后, 此一定数量的线程同时唤醒, 也可以调用countDown()方法减少计数到0,也会唤醒线程

CountDownLatch latch = new CountDownLatch(5);
latch.countDown();  //手动减少计数
latch.await();      //线程等待并减少计数

CyclicBarrier 类 循环屏障

  1. 等所有子线程都await()之后, 先执行构造中的Runnable(barrierAction)汇总任务以合并子线程处理结果,然后所有子线程才能继续往下执行
  2. 体现出循环性, 在所有子线程都被唤醒后, 子线程可以继续调用await(),然后等待下一次唤醒并处理

Semaphore 信号量类 --底层AQS
3. 流量控制— acquire()方法获取执行许可(执行许可有限)—>release()释放执行许可
4. 注意事项:不使用acquire(),直接调用release(),会直接增加许可证数量

Exchanger 类:用于两个线程的协作–只支持两个线程
两个线程都调用exchange()方法, 互相交换数据,该方法会阻塞线程

Callable和FutureTask:解决普通线程执行没有返回值的问题

  1. FutureTask 实现的接口, 他可以作为一个runnable在Thread里直接使用, 又实现了Future接口, 他可以get()结果, 这块看看源码就知道
XXXCallable _temp = new XXXCallable();
FutureTask<xxx> task = new FutureTask<xxx>(_temp);
new Thread(task).start();
//获取结果
task.get();  //会在结果获取之前阻塞线程
//中断任务需要在callable里响应interrupt标志位, 同时调用task的取消方法
task.cancel(true); //本质就是interrupt() 方法来中断线程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值