赞
踩
在ChromeDriver自动化开发过程中,左耳碰到了一个问题,就是ChromeDriver驱动是比较消耗资源的存在,所以要对它进行管制,正好左耳了解线程池的机制,其作用就是节约资源,避免不必要的创建与销毁开销,而ChromeDriver不也是如此么。
流程分析
2.1 数据初始化
2.2 getPool根据coreSize判断是否新增资源,其中count要使用原子自增
2.3 Worker的status要设置为volatile,让其他线程可见
public class ChromeDriverPool { private static ConcurrentHashMap<Integer,Object> pool ;//线程池 private static int coreSize = 2;核心线程池,一直驻留的资源 private static int maxSize = 10;//TODO 设置最大数量资源,用于解决瞬时并发,瞬时并发过后要定时去识别空闲的释放掉,保留coreSize的资源 private static AtomicInteger count = new AtomicInteger(0);//原子自增!! static { //驱动初始化 System.setProperty("webdriver.chrome.driver", "/usr/local/bin/chromedriver"); if (System.getProperty("os.name").toLowerCase().contains("windows")) { System.setProperty("webdriver.chrome.driver", "C:\\usr\\webser\\chromedriver.exe"); } pool = new ConcurrentHashMap<>(); } private ChromeDriverPool(){ } public static void init(int coreSize){//线程池数量初始化 ChromeDriverPool.coreSize = coreSize; } public static Worker getPool(){ if(count.getAndIncrement() < coreSize){//自增!!! return push(new Worker()); }else{ return pop(); } } public static Worker push(Worker worker){ pool.put(count.get(),worker); return worker; } /** * 循环获取未使用的资源 * @return */ public static Worker pop(){ Set<Map.Entry<Integer, Object>> sets = pool.entrySet(); Iterator<Map.Entry<Integer, Object>> its = sets.iterator(); while(its.hasNext()){ Map.Entry<Integer, Object> workEntry = its.next(); Worker work = (Worker)workEntry.getValue(); if(work.status == 1){ return work; } } return null; } public static class Worker{ private ChromeDriver driver; /** * 状态修改要让其他线程可见 * 1就绪 2运行 */ private volatile int status; public Worker(){ driver = new ChromeDriver(); status = 1; } public void shutdown(){ this.status = 1; } public void start(){ this.status = 2; } public ChromeDriver getDriver() { return driver; } } }
2.4 模拟并发环境测试
public static void main(String[] args) throws Exception { //模拟并发 int parallelSize = 10; final CountDownLatch latch = new CountDownLatch(1); ExecutorService pool = Executors.newFixedThreadPool(parallelSize); for (int i = 0; i < parallelSize; i++) { pool.execute(new Runnable() { @Override public void run() { ChromeDriverPool.Worker work = null; try { latch.await();//阻塞所有线程 System.out.println(Thread.currentThread().getName()); while (true) {//业务需求,一直等待直到获取到驱动 work = ChromeDriverPool.getPool(); if (work != null) { break; } Thread.sleep(1000); } work.start(); ChromeDriver driver = work.getDriver(); System.out.println(Thread.currentThread().getName()+":"+driver); Thread.sleep(1000 * 10); } catch (Exception e) { System.out.println(e.getMessage()); }finally { work.shutdown(); } } }); } latch.countDown();//开炮 }
到此一个简单的线程池应用就完成了,让资源重复利用,节省开销,那么有没有要优化的点呢?
我们知道ThreadPoolExecutor有几个核心参数(更多ThreadPoolExecutor知识请参考 链接)
corePoolSize
为线程池的基本大小。maximumPoolSize
为线程池最大线程大小。keepAliveTime
和 unit
则是线程空闲后的存活时间。workQueue
用于存放任务的阻塞队列。handler
当队列和最大线程池都满了之后的饱和策略。我们可以按此去优化我们的程序,比如maximumPoolSize的应用
,可以解决瞬时并发的问题。到此我们就结束这一篇章,有兴趣的朋友可以尝试实现一下maximumPoolSize。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。