JAVA Concurrent.util工具类的使用

一、CyclicBarrier的使用:

假设有只有的一个场景:每个线程代表一个跑步运动员,当运动员都准备好后,才一起出发,只要有一个没有准备好,大家都等待。

CyclicBarrier示例:

public class UseCyclicBarrier {
public static void main(String[] args) {
//参数表示3个线程一起准备OK继续执行,少一个线程所有线程一直阻塞。多一个线程多出来的线程会一直阻塞不执行只有参数个数的线程会继续执行。
CyclicBarrier barrier=new CyclicBarrier(3);
Runner zs=new Runner(barrier, “张三”);
Runner ls=new Runner(barrier, “李四”);
Runner ww=new Runner(barrier, “王五”);
Runner ll=new Runner(barrier, “丽丽”);
ExecutorService executor=Executors.newFixedThreadPool(3);
executor.execute(zs);
executor.execute(ls);
executor.execute(ww);
// executor.execute(ll);
executor.shutdown();
}
static class Runner implements Runnable{
private CyclicBarrier barrier;
private String name;
public Runner(CyclicBarrier barrier, String name) {
this.barrier = barrier;
this.name = name;
}
@Override
public void run() {
try {
int time=1000*(new Random()).nextInt(5);
System.out.println(name+“睡眠时间:”+time);
Thread.sleep(time);
System.out.println(name+“准备OK!”);
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(name+"–gogogogo");
}
}
}

输出结果:

张三睡眠时间:4000
王五睡眠时间:3000
李四睡眠时间:1000
李四准备OK!
王五准备OK!
张三准备OK!
张三–gogogogo
李四–gogogogo
王五–gogogogo

注意:CyclicBarrier barrier=new CyclicBarrier(3);//参数表示3个线程一起准备OK继续执行,少一个线程所有线程一直阻塞。多一个线程多出来的线程会一直阻塞不执行只有参数个数的线程会继续执行。

二、CountDownLacth使用:

它经常用于监听某些初始化操作,等初始化执行完毕后,通知主线程继续工作。

CountDownLatch 示例

public static void main(String[] args) {
	//初始化参数2表示需要等待两个子线程的countDown()方法的通知
	final CountDownLatch countDown=new CountDownLatch(2);
	Thread t1=new Thread(new Runnable() {			
		@Override
		public void run() {
			try {
				System.out.println("进入线程t1等待其他线程处理完成...");
				countDown.await();
				System.out.println("t1线程继续执行...");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	},"t1");
	Thread t2=new Thread(new Runnable() {			
		@Override
		public void run() {
			try {
				System.out.println("t2线程进入初始化操作...");
				Thread.sleep(3000);
				System.out.println("t2线程初始化完毕,通知t1线程继续执行...");
				countDown.countDown();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	},"t2");
	Thread t3=new Thread(new Runnable() {			
		@Override
		public void run() {
			try {
				System.out.println("t3线程进入初始化操作...");
				Thread.sleep(5000);
				System.out.println("t3线程初始化完毕,通知t1线程继续执行...");
				countDown.countDown();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	},"t3");
	t1.start();
	t2.start();
	t3.start();
}

输出结果

进入线程t1等待其他线程处理完成…
t3线程进入初始化操作…
t2线程进入初始化操作…
t2线程初始化完毕,通知t1线程继续执行…
t3线程初始化完毕,通知t1线程继续执行…
t1线程继续执行…

初始化CountDownLatch的参数表示需要等待两个子线程的countDown()方法的通知,当达到给定的2的时候其他的线程在调用countDown()也不起作用。

CyclicBarrier和CountDownLacth的区别

CyclicBarrier:多个线程等待完成准备然后在同时各自执行自己的线程。
CountDownLatch:一个线程等待多个线程执行完成通知。

三、Callable和Future使用

Future模式非常适合处理很耗时的业务逻辑时进行使用,可以有效的减小系统的响应时间,提高系统的吞吐量。

Future示例:

public class UseFuture implements Callable{

private String params;

public UseFuture(String params) {
	this.params=params;
}
@Override
public String call() throws Exception {
	Thread.sleep(3000);
	return "根据请求参数:"+params+"返回结果!";
}

public static void main(String[] args) throws InterruptedException, ExecutionException {
	String params="我要大美女";
	FutureTask<String> futureTask1=new FutureTask<>(new UseFuture(params+"1"));
	FutureTask<String> futureTask2=new FutureTask<>(new UseFuture(params+"2"));
	ExecutorService es=Executors.newFixedThreadPool(2);
	//submit和execute的区别:submit有返回值,execute无返回值
	Future f=es.submit(futureTask1);
	es.execute(futureTask2);
	System.out.println("请求完毕!");
	//f.get()任务一处理完就返回一个NULL
	System.out.println(f.get());
	while(true){
		if(f.get()==null){
			System.out.println("任务执行完毕");
			break;
		}
	}	
	
	try {
		Thread.sleep(4000);			
		System.out.println("返回结果1:"+futureTask1.get());
		System.out.println("返回结果2:"+futureTask2.get());
	} catch (Exception e) {
		e.printStackTrace();
	}
	
	es.shutdown();
}

}

输出结果:

请求完毕!
null
任务执行完毕
返回结果1:根据请求参数:我要大美女1返回结果!
返回结果2:根据请求参数:我要大美女2返回结果!

总结 :
ExecutorService es=Executors.newFixedThreadPool(2);
// ** submit和execute的区别 **:submit有返回值,execute无返回值
Future f=es.submit(futureTask1);
es.execute(futureTask2);
上面两个返回结果同时打印表示futureTask1.get()异步获取结果。

三、信号量

描述:在Semaphore信号量非常适合高并发访问,新系统在上线之前,要对系统的访问量进行评估,当然这个值肯定不是随便拍拍脑袋就能想出来的,是经过以往的经验、数据、历年的 访问,以及推广力度进行一个合理的评估,当然评估标准不能太大也不能太小,太大的话投入的资源达不到实际效果,纯粹浪费资源,太小的话,某个时间点一个高峰值的访问量上来直接可以压垮系统。

相关概念:

PV(page view) 网站的总访问量,页面浏览量或点击量,用户每刷新一次就会 被记录一次。
UV(unique Visitor)访问网站的一台电脑客户端为一个访客。一般来讲,时间上以00:00-24:00之内相同IP的客户端只记录一次。
QPS(query per second)即每秒查询数,qps很大程度上代表了系统业务上的繁忙程度,每次请求的背后,可能对应着多次磁盘I/O,多次网络请求,多个cpu时间片等。我们通过qps可以非常直观的了解当前系统业务情况,一旦当前qps超过所设定的预警阈值,可以考虑增加机器对集群扩容,以免压力过大导致宕机,可以根据前期的压力测试得到估值,在结合后期综合运维情况,估算出阈值。
RT(response time)即请求的响应时间,这个指标非常关键,直接说明前端用户的体验,因此任何系统设计师都想降低rt时间。
当然还涉及cpu、内存、网络、磁盘等情况,更细节的问题很多,如select、update、delete/ps等数据库层面的统计。

容量评估:一般来说通过开发、运维、测试、以及业务等相关人员,综合出系统的一系列阈值,然后我们根据关键阈值如qps、rt等,对系统进行有效的变更。

一般来讲,我们进行多轮压力测试以后,可以对系统进行峰值评估,采用所谓的80/20原则,即80%的访问请求将在20%的时间内达到。这样我们可以根据系统对应的PV计算出峰值qps。

qps=(总PV * 80%)/(606024*20%)

然后在将总的峰值QPS除以单台机器所能承受的最高的qps值,就是所需要机器的数量:机器数=总的峰值qps/压测得出的单击极限qps

当然不排除系统在上线前进行大型促销活动,或者双十一,双十二热点事件、遭受到DDos攻击等情况,系统的开发和运维人员急需要了解当前系统运行的状态和负载情况,一般都会有后台系统去维护。

semaphore 信号量示例:

public class UseSemaphore {
public static void main(String[] args) {
//线程池
ExecutorService es=Executors.newCachedThreadPool();
//只能5个线程同时访问
final Semaphore semaphore=new Semaphore(5);
//模拟20个线程同时访问
for (int i = 0; i < 20; i++) {
final int NO=i;
Runnable r=new Runnable() {
@Override
public void run() {
try {
//拿到许可
semaphore.acquire();
System.out.println("Accessing: "+NO);
//模拟实际业务逻辑
Thread.sleep((long) (Math.random()*10000));
//访问完毕,释放
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
es.submit®;
}
es.shutdown();
}

}

输出结果:

Accessing: 1
Accessing: 3
Accessing: 5
Accessing: 9
Accessing: 13
Accessing: 17
Accessing: 7
Accessing: 11
Accessing: 15
Accessing: 8
Accessing: 19
Accessing: 12
Accessing: 16
Accessing: 2
Accessing: 0
Accessing: 6
Accessing: 4
Accessing: 10
Accessing: 14
Accessing: 18
总结:第一次输出5个。后面保证每次只有5个活跃的线程。

猜你喜欢

转载自blog.csdn.net/yanghzaini/article/details/84192322