【并发编程学习】3.线程并发工具类(Fork/Join、CountDownLatch、CyclicBarrier、Semaphore、Exchange使用示例)

1.Fork/Join 框架

工作密取: A线程、B线程分别执行5个任务,A执行完5个之后发现B还没执行完,就帮助B执行。
思想: 分而治之,大任务拆分(fork)成多个小任务,在进行join的过程。
实现: ForkTask抽象类下的两个抽象类:
RecursiveTask:任务有返回值
RecursiceAction:任务没有返回值
例子: 同步方法带返回值的例子,计算4000个2的和

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
class ForkJoinTest extends RecursiveTask<Integer>{
	private static final int THRESHOLD=100;
	private int []src;//统计的数据
	private int formIndex;//开始下标
	private int endIndex;//结束下标
	public ForkJoinTest(int []src,int formIndex,int endIndex) {
		this.src=src;
		this.formIndex=formIndex;
		this.endIndex=endIndex;
	}
	@Override
	protected Integer compute() {
		//判断是否满足条件
		if (endIndex-formIndex<THRESHOLD) {
			//满足,进行小任务计算
			int sum=0;
			for (int i =formIndex;i<=endIndex;i++) {
				sum+=src[i];
			}
			return sum;
		}else{//不满足,任务拆分
			int mid=(formIndex+endIndex)>>1;
			ForkJoinTest left=new ForkJoinTest(src,formIndex,mid);
			ForkJoinTest right=new ForkJoinTest(src,mid+1,endIndex);
			//进行整合,递交给任务池
			invokeAll(left,right);
			return left.join()+right.join();
		}
	}
}
public class ThreadStudy {

	public static void main(String[] args)  {
		int src[]=new int[4000];//初始化
		for (int i = 0; i < src.length; i++) {
			src[i]=2;
		}
		//任务池
		ForkJoinPool forkJoinPool=new ForkJoinPool();
		//自己写的任务
		ForkJoinTest task=new ForkJoinTest(src, 0, 3999);
		//提交给任务池
		forkJoinPool.invoke(task);
		System.out.println(task.join());
	}

}

例子2:Java并发编程—Fork/Join

2.CountDownLatch使用示例

作用: 一个线程等待其他的线程完成工作以后在执行。
注意:扣除点和线程数可以不同。
实验内容: 5个线程有6个扣除点,主线程等初始化完成后执行。

import java.util.concurrent.CountDownLatch;

public class ThreadStudy {
	//6个扣除点
	static CountDownLatch latch=new CountDownLatch(6);
	//初始化线程
	private static class InitThread implements Runnable{
		public void run() {
			System.out.println("Thread_"+Thread.currentThread().getId()+"ready");
			latch.countDown();//初始化工作完成了
			//此时初始化线程可以继续做自己的工作
			System.out.println("Thread_"+Thread.currentThread().getId()+"readyEnd");
		}
	}
	//业务线程
	private static class BusinessThread implements Runnable{
		public void run() {
			try {
				//等待初始化线程完成
				latch.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			//业务线程自己的工作
			for (int i = 0; i < 5; i++) {
				System.out.println("Thread_"+Thread.currentThread().getId()+"working");
			}
			System.out.println("Thread_"+Thread.currentThread().getId()+"end");
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		//同一个线程 扣除两个
		new Thread(()->{
			latch.countDown();
			latch.countDown();
		}).start();
		new Thread(new BusinessThread()).start();
		//扣除四个
		for (int i = 0; i < 4; i++) {
			new Thread(new InitThread()).start();
		}
		//不一定是一个线程可以await,此时让主线程await
		latch.await();
		System.out.println(Thread.currentThread().getName()+"done");
	}
}

输出:
某次结果1:

Thread_15ready
Thread_15readyEnd
Thread_14ready
Thread_14readyEnd
Thread_13ready
Thread_13readyEnd
Thread_12ready
Thread_12readyEnd
maindone  //前面初始化工作做完了(扣除点已全部扣除),Main线程可以继续
Thread_11working//业务线程工作
Thread_11working//业务线程工作
Thread_11working//业务线程工作
Thread_11working//业务线程工作
Thread_11working//业务线程工作
Thread_11end//业务线程结束

某次结果2:

Thread_12ready
Thread_14ready
Thread_14readyEnd
Thread_13ready
Thread_15ready
Thread_15readyEnd
Thread_12readyEnd
Thread_11working
Thread_11working
Thread_11working
Thread_11working
Thread_11working
Thread_11end
Thread_13readyEnd //只要扣除点扣完了,就会通知业务线程和main线程,init线程做自己的工作
maindone

3.CyclicBarrier使用示例

作用: 让一组线程达到某个屏障,被阻塞,一直到组内最后一个线程达到屏障时,屏障开放,所有被阻塞的线程会继续运行。

  • 例子1:Thread-0、a、z三个线程都到达屏障后,继续运行
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class ThreadStudy {
	//三个线程都到达屏障,屏障开放
	private static CyclicBarrier cyclicBarrier=new CyclicBarrier(3);
	private static class TestThread implements Runnable{
		String name;
		public TestThread(String name) {
			this.name=name;
		}
		@Override
		public void run() {	
			Thread.currentThread().setName(name);		
			try {
				//休眠的时间,模拟业务
				int time=1000+Integer.valueOf(name.toCharArray()[0])*10;
				Thread.currentThread().sleep(time);
				System.out.println(time+"after,Thread-" +Thread.currentThread().getName()+" is running");
				cyclicBarrier.await();
				System.out.println("Thread-" +Thread.currentThread().getName()+" end");
			} catch (InterruptedException |BrokenBarrierException e) {
				e.printStackTrace();
			}
		}
	}
	public static void main(String[] args) throws InterruptedException {
		new Thread(new TestThread("0")).start();
		new Thread(new TestThread("z")).start();
		new Thread(new TestThread("a")).start();
	}
}

输出:先各自运行
在这里插入图片描述
再一同输出await之后的语句
在这里插入图片描述

  • 例子2:CyclicBarrier(int parties, Runnable barrierAction)方法
    修改CyclicBarrier:
//三个线程都到达屏障,屏障开放,barrierAction定义的任务会执行
	private static CyclicBarrier cyclicBarrier=new CyclicBarrier(3,()->{
		System.out.println("after 0  a z ");
	});

输出:
在这里插入图片描述

4.CountDownLatch和CyclicBarrier比较

(1)CountDownLatch由后面的其他线程决定,CyclicBarrier由任务本身的几个线程决定
(2)CountDownLatch放行条件>=线程数,CyclicBarrier放行条件=线程数

5.Semaphare实现数据库连接池

作用: 控制同时访问某个特定资源的线程数量,用在流量控制
例子

class DpPoolSemaphore {
	//数据库连接池的数量
	private final static int POOL_SIZE=10;
	//可用数据库连接,已用数据库连接
	private final Semaphore usefull,useless;
	public DpPoolSemaphore(){
		this.usefull=new Semaphore(POOL_SIZE);
		this.useless=new Semaphore(0);
	}
	//存放数据库连接
	private static LinkedList<Connection> pool=new LinkedList<>();
	static{
		for (int i = 0; i < POOL_SIZE; i++) {
			pool.addLast(new MyConnection());
		}
	}
	//归还连接
	public void returnConnect(Connection connection)throws InterruptedException{
		if (connection!=null) {
			useless.acquire();//已用连接-1
			synchronized (pool) {
				pool.addLast(connection);
			}
			usefull.release();//可用连接释放资源
		}
	}
	//拿连接
	public Connection takeConnection(Connection connection)throws InterruptedException{
		usefull.acquire();//获取可用数据连接
		Connection conn;
		synchronized (pool) {
			conn=pool.removeFirst();
		}
		useless.release();//释放已用连接,已用数据连接加一
		return conn;
	} 
}

6.Exchange使用示例

作用: 两个线程间数据交换。
例子:交换两个线程的int数据

import java.util.concurrent.Exchanger;
public class ThreadStudy {
	//三个线程都到达屏障,屏障开放,barrierAction定义的任务会执行
	private static Exchanger<Integer> exchanger=new Exchanger<>();
	public static void main(String[] args) throws InterruptedException {
		new Thread(()->{
			int num1=1;
			try {
				System.out.println(Thread.currentThread().getName()+"-----"+num1);
				Thread.currentThread().sleep(1000);
				//先到达这个位置,阻塞,等待与它交换的线程到达之后进行交换
				num1=exchanger.exchange(num1);
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"-----"+num1);
		}).start();
		new Thread(()->{
			int num1=2;
			try {
				System.out.println(Thread.currentThread().getName()+"-----"+num1);
				Thread.currentThread().sleep(2000);
				num1=exchanger.exchange(num1);
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"-----"+num1);
		}).start();	
	}
}

输出:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值