性能测试作到后面,一些特殊的场景利用经常使用的现成工具知足不了需求,因此你须要学习java写一些特定协议的压测脚本,那你不得不研究多线程或线程池,而此时你也必定会遇到java并发编程中的几个类,今天重点讲解这3个类,CountDownLanch、CyclicBarrier、Semaphore,但愿你们之后看到的时候知道是干吗用的。java
接下来,我就最近学习的成果,下面和你们举例子讲解一下,帮助理解。web
1CountDownLanch数据库
场景编程
工做中每每会遇到须要异步处理的任务,此时咱们就会利用多线程的方式去处理,即启动子线程去执行任务,而此时主线程阻塞,等待全部的子线程完成任务后,再去作一些汇总统计工做。多线程
CountDownLanch 是一个倒数计数器, 给一个初始值(>=0), 而后每一次调用countDown就会减1, 这很符合等待多个子线程结束的场景: 一个线程结束的时候, countDown一次, 直到全部的线程都countDown了 , 那么全部子线程就都结束了。并发
先看看CountDownLanch提供的方法。app
await: 会阻塞等待计数器减小到0位置. 带参数的await是多了等待时间。异步
countDown: 将当前的计数减1。ide
getCount(): 返回当前的计数。函数
显而易见, 咱们只须要在子线程执行以前, 赋予初始化countDownLanch, 并赋予线程数量为初始值。
每一个线程执行完毕的时候, 就countDown一下。主线程只须要调用await方法, 能够等待全部子线程执行结束。
例子
package ht.test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class CountDownLatchTest {
// 参数是2表示对象执行2次countDown方法才能释放锁
static CountDownLatch c = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
// 定义线程数
int subThreadNum = 5;
// 取得一个倒计时器,从5开始
CountDownLatch countDownLatch = new CountDownLatch(subThreadNum);
// 依次建立5个线程,并启动
for (int i = 0; i < subThreadNum; i++) {
SubThread runnablethread = new SubThread(5000, countDownLatch);
new Thread(runnablethread).start();
}
// 主线程工做,此处能够添加一些额外的工做
// mainWork();
// 等待全部的子线程结束
countDownLatch.await();
System.out.println("all all all Main Thread work done!");
}
static class SubThread implements Runnable {
private CountDownLatch countDownLatch;
private long workTime;
public SubThread(long workTime, CountDownLatch countDownLatch) {
this.workTime = workTime;
this.countDownLatch = countDownLatch;
}
public void run() {
// TODO Auto-generated method stub
try {
System.out.println("线程Id:" + Thread.currentThread().getId() + " Sub thread is starting!");
Thread.sleep(workTime);
System.out.println("线程Id:" + Thread.currentThread().getId() + " Sub thread is stopping!");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// 线程结束时,将计时器减一
countDownLatch.countDown();
}
}
}
}
2CyclicBarrier
场景
咱们在作压测的时候,如要真正的并发,那么在建立线程成功后须要等待其余线程也建立好了,一块儿等着,同时发送请求,此时就用到了CyclicBarrier。
CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要作的事情是,让一组线程到达一个屏障(也能够叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,全部被屏障拦截的线程才会继续运行。
例子
package ht.test;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
// 初始化线程等待的个数,当调用await()函数的次数和这里的数值一致时候,接下去执行。
static CyclicBarrier c = new CyclicBarrier(2);
public static void main(String[] args) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 子线程
c.await();
} catch (Exception e) {
}
System.out.println(1);
}
}).start();
try {
// 主线程,若此处注册掉,执行结果为2,而且子线程一直阻塞着
c.await();
} catch (Exception e) {
}
System.out.println(2);
}
}
3Semaphore
场景
有时候并发太大的时候,咱们须要人工的控制,譬如一些数据库的链接数这样子的,资源毕竟有限的,不可能无限去建立链接,此时咱们就须要利用Semaphore去控制。
Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它经过协调各个线程,以保证合理的使用公共资源。能够控制系统的流量,拿到信号量的线程能够进入,不然就等待。经过acquire()和release()获取和释放访问许可。
例子
package ht.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class TestSemaphore {
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) 10000);
// 访问完后,释放
semp.release();
} catch (InterruptedException e) {
}
}
};
exec.execute(run);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// System.out.println(semp.getQueueLength());
// 退出线程池
exec.shutdown();
}
}
不知道,你有没有理解,在此也只是抛砖引玉一下,你们在实践中能够继续学习研究。
更多其余测试内容能够参考连接文末更多测试好文章