CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。在一些应用场合中,需要等待某个条件达到要求后才能做后面的事情;同时当线程都完成后也会触发事件,以便进行后面的操作。 这个时候就可以使用CountDownLatch。
本文主要介绍CountDownLatch的一个具体使用——字符串敏感字过滤。字符串敏感字过滤是一个常用的功能点,这里使用的敏感字过滤方法主要参考 敏感词过滤算法实现这边博客。而使用CountDownLatch的主要目的是为了提高敏感字过滤的效率。
//将字符串按照每1024个字符一组进行截取 private static final int PRE_LENGTH = 1024; public String filter(String textStr) { int length = textStr.length(); int latchCount = length / PRE_LENGTH + 1; String[] temp = new String[latchCount]; Worker[] workerGroup = new Worker[latchCount]; for (int i = 0; i < latchCount; i++) { if (i + 1 == latchCount) { // 最后一次 temp[i] = textStr.substring(i * PRE_LENGTH); } else { temp[i] = textStr.substring(i * PRE_LENGTH, (i + 1) * PRE_LENGTH); } } StringBuilder builder = new StringBuilder(length); CountDownLatch latch = new CountDownLatch(latchCount); for (int i = 0; i < latchCount; i++) { workerGroup[i] = new Worker(temp[i], sw, latch); workerGroup[i].start(); } try { latch.await(); for (Worker tempWorker : workerGroup) { builder.append(tempWorker.textStr); } } catch (InterruptedException e) { e.printStackTrace(); } return builder.toString(); }
static class Worker extends Thread { String textStr; String replaceStr; KWSeeker kwseeker; CountDownLatch latch; public Worker(String textStr, KWSeeker kwseeker, CountDownLatch latch) { this.textStr = textStr; this.kwseeker = kwseeker; this.latch = latch; } public void run() { try { textStr = doWork(); } catch (Exception e) { e.printStackTrace(); } finally { latch.countDown(); } } private String doWork() { String str = kwseeker.replace(textStr, fragment); return str; } }
我们可以看到:
1、CountDownLatch初始化的count为字符串按照每1024个字节截取的数组数量 latchCount
2、创建 latchCount 个线程,并执行
3、只有当所有线程执行完成,并调用 latch.countDown()后 latch.await()会被唤起,继续执行后续的代码。
测试代码
protected List<Keyword> init() { List<Keyword> words = new ArrayList<>(); try { for (String line : TextLineIO .lineSeq("D:\\keyword.txt")) { words.add(new Keyword(line)); } } catch (Throwable e) { e.printStackTrace(); } return words; } public static void main(String[] args) throws IOException { Testkeyword t = new Testkeyword(); t.init(); String path="D:\\word.txt"; BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(path))); StringBuffer buffer = new StringBuffer(); String line = " "; while ((line = reader.readLine()) != null){ buffer.append(line); } String textStr=buffer.toString(); System.out.println("过滤字符串长度:"+textStr.length()); long begin=System.currentTimeMillis(); t.filter(textStr); System.out.println("消耗时间:"+(System.currentTimeMillis()-begin)+"ms"); }
测试结果:
--------未使用多线程-----------
过滤字符串长度:31878
消耗时间:215ms
-------使用多线程--------------
过滤字符串长度:31878
消耗时间:47ms