Concurrent.Util常用类
CyclicBarrier
假设有一个场景:每个线程代表一个运动员,当运动员都准备好才一起出发,只要有一个没准备好就大家都等待。
public class UseCyclicBarrier {
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 {
Thread.sleep(1000*(new Random().nextInt(5)));
System.out.println(name+" 准备OK.");
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(name+" Go!!!");
}
}
public static void main(String[] args) {
//3表示要等待三个线程
CyclicBarrier barrier = new CyclicBarrier(3);
ExecutorService executor = Executors.newFixedThreadPool(3);
executor.submit(new Thread(new Runner(barrier,"zhangsan")));
executor.submit(new Thread(new Runner(barrier,"lisi")));
executor.submit(new Thread(new Runner(barrier,"wangwu")));
executor.shutdown();
}
}
CountDownLatch
它经常用于监听某些初始化操作,等初始化执行完毕后,通知主线程继续工作。
public class UseCountDownLatch {
public static void main(String[] args) {
final CountDownLatch countDownLatch = new CountDownLatch(2);
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
try {
System.out.println("进入线程1"+"等待其他线程处理完成...");
countDownLatch.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线程继续...");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t2");
Thread t3 = new Thread(new Runnable(){
@Override
public void run() {
try {
System.out.println("t3线程进行初始化操作...");
Thread.sleep(4000);
System.out.println("t3线程初始化完毕,通知t1线程继续...");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t3");
t1.start();
t2.start();
t3.start();
}
}
CountDownLatch与CyclicBarrier的区别
CountDownLatch是一个线程在等待其他线程的通知,然后一个线程执行。
CyclicBarrier是几个线程都参与阻塞。当阻塞条件达到,所有的线程都同时执行。
Callable和Future的使用
类似于之前Future模式的使用,JDK给予了一个实现的封装。
public class UseFuture implements Callable<String>{
private String para;
public UseFuture(String para){
this.para=para;
}
/**
* 真实的业务逻辑,其执行可能很慢
*/
@Override
public String call() throws Exception {
//模拟执行耗时
Thread.sleep(3000);
String result = this.para+"处理完成";
return result;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
String queryStr = "query";
//构建FutureTask,并且传入需要真正进行业务处理的类,该类一定是实现了Callable接口的类
FutureTask<String> future = new FutureTask<String>(new UseFuture(queryStr));
FutureTask<String> future2 = new FutureTask<String>(new UseFuture(queryStr));
//创建一个固定线程的线程池且线程数为1
ExecutorService executor = Executors.newFixedThreadPool(2);
//这里提交任务future,则开启线程执行RealData的call()方法执行
//submit和executor的区别:第一点 submit可以传入实现callable接口的实力对象 第二点 submit方法有返回值
Future f1 = executor.submit(future);
Future f2 = executor.submit(future2);
System.out.println("请求完毕");
//当返回值为null 表示执行结束
/*System.out.println(f.get());
while(true){
if(f.get()==null){
System.out.println("当前线程执行完毕...");
break;
}
}*/
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//调用获取数据方法,如果call()方法没有执行完成,则依旧会等待,get()方法异步获取执行结果
System.out.println("数据:"+future.get());
System.out.println("数据:"+future2.get());
executor.shutdown();
}
}
Semaphore信号量非常适合高并发访问,新系统上线之前,要对新系统的访问量进行评估,当然这个值不能太大也不能太小。太大的话浪费资源,太小的话某个高峰值的访问量上来直接压垮系统。
相关概念:
PV(page view)网站的总访问量,页面浏览量或点击量,用户没刷新一次就会被记录一次。
UV(unique visitor)访问网站的一台电脑客户端为一个访客。一般来说0点-24点只能相同ip的客户端只记录一次。
QPS(query per seconds)即每秒查询量
RT(response time)请求的响应时间。
峰值qps=(总PV*0.8)/(60*60*24*0.2)
/**
* 使用semaphore进行限流的控制
* @author Carl_Hugo
*/
public class UseSemaphore {
public static void main(String[] args) {
//没有容量限制的线程池
ExecutorService exec = Executors.newCachedThreadPool();
//只能5个线程同时访问
final Semaphore semp = new Semaphore(5);
//模拟20个客户端访问
for(int index=0;index<20;index++){
final int NO = index;
Runnable run = new Runnable(){
@Override
public void run() {
try {
//获取许可
semp.acquire();
System.out.println("Accessing:"+NO);
//模拟实际业务逻辑
Thread.sleep((long)(Math.random()*10000));
//访问完后释放
semp.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
exec.execute(run);
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
exec.shutdown();
}
}